hph cache mechanism

The buffer
buffer is a memory address space. The default size of the Linux system is generally 4096 (4kb), which is a memory page. It is mainly used to store the data transfer area between devices with different speeds or devices with different priorities. Through the buffer, the mutual waiting between the processes can be reduced. Here is a simple example. When you open a text editor to edit a file, every time you enter a character, the operating system does not immediately write the character directly to the disk, but first writes it to the buffer. When a buffer is full, the data in the buffer will be written to the disk. Of course, when the kernel function flush() is called, it is mandatory to write the dirty data in the buffer back to the disk.

In the same way, when echo and print are executed, the output is not immediately sent to the client browser through tcp for display, but the data is written to the php buffer. The php output_buffering mechanism means that a new queue is established before the tcp buffer, and the data must pass through the queue. When a php buffer is full, the script process will hand over the output data in the php buffer to the system kernel to be transmitted to the browser by tcp for display. Therefore, the data will be written to these places in sequence: echo/print -> php buffer -> tcp buffer -> browser

php output_buffering
By default, the php buffer is enabled, and the default value of the buffer is 4096, which is 4kb. You can find the output_buffering configuration in the php.ini configuration file. When echo, print, etc. output user data, the output data will be written to php output_buffering, until the output_buffering is full, the data will be sent to the browser via tcp show. You can also manually activate the php output_buffering mechanism through ob_start(), so that even if the output exceeds 4kb data, the data is not really sent to tcp to the browser, because ob_start() sets the php buffer space to be large enough. Only until the script ends, or the ob_end_flush function is called, will the data be sent to the client browser.

1. When output_buffering=4096, and output less data (less than one buffer)

Copy the code The code is as follows:

<?php
for ($i = 0; $i < 10; $i++) {
echo $i . '<br/>';
sleep($i + 1); //
}
?>


Phenomenon: There is not intermittent output every few seconds, but the output can be seen at one time until the end of the response, and the browser interface remains blank until the server script processing ends. This is because the amount of data is too small and php output_buffering is not full. The order of writing data is echo->php buffer->tcp buffer->browser

 

2. When output_buffering=0, and output less data (less than one buffer)

Copy the code The code is as follows:

<?php
//通过ini_set('output_buffering', 0)并不生效
//应该编辑/etc/php.ini,设置output_buffering=0禁用output buffering机制
//ini_set('output_buffering', 0); //彻底禁用output buffering功能
for ($i = 0; $i < 10; $i++) {
echo $i . '<br/>';
flush(); //通知操作系统底层,尽快把数据给客户端浏览器
sleep($i + 1); //
}
?>


现象:与刚才显示并不一致,禁用了php buffering机制之后,在浏览器可以断断续续看到间断性输出,不必等到脚本执行完毕才看到输出。这是因为,数据没有在php output_buffering中停留。写数据的顺序依次是echo->tcp buffer->browser

 

3.当output_buffering=4096.,输出数据大于一个buffer,不调用ob_start()

复制代码 代码如下:

#//创建一个4kb大小的文件
$dd if=/dev/zero of=f4096 bs=4096 count=1
<?php
for ($i = 0; $i < 10; $i++) {
echo file_get_contents('./f4096') . $i . '<br/>';
sleep($i +1);
}
?>


现象:响应还没结束(http连接没有关闭),断断续续可以看到间断性输出,浏览器界面不会一直保持空白。尽管启用了php output_buffering机制,但依然会间断性输出,而不是一次性输出,是因为output_buffering空间不够用。每写满一个php buffering,数据就会发送到客户端浏览器。

 

4.当output_buffering=4096, 输出数据大于一个tcp buffer, 调用ob_start()

复制代码 代码如下:

<?php
ob_start(); //开启php buffer
for ($i = 0; $i < 10; $i++) {
echo file_get_contents('./f4096') . $i . '<br/>';
sleep($i + 1);
}
ob_end_flush();
?>


现象:直到服务端脚本处理完成,响应结束,才看到完整输,输出间隔时间很短,以至你感受不到停顿。在输出之前,浏览器一直保持着空白界面,等待服务端数据。这是因为,php一旦调用了ob_start()函数,它会将php buffer扩展到足够大,直到ob_end_flush函数调用或者脚本运行结速才发送php buffer中的数据到客户端浏览器。

output buffering函数

 

 

1.ob_get_level
返回输出缓冲机制的嵌套级别,可以防止模板重复嵌套自己。

1.ob_start
激活output_buffering机制。一旦激活,脚本输出不再直接出给浏览器,而是先暂时写入php buffer内存区域。

php默认开启output_buffering机制,只不过,通过调用ob_start()函数据output_buffering值扩展到足够大。也可以指定$chunk_size来指定output_buffering的值。$chunk_size默认值是0,表示直到脚本运行结束,php buffer中的数据才会发送到浏览器。如果你设置了$chunk_size的大小,则表示只要buffer中数据长度达到了该值,就会将buffer中的数据发送给浏览器。

当然,你可以通过指定$ouput_callback,来处理buffer中的数据。比如函数ob_gzhandler,将buffer中的数据压缩后再传送给浏览器。

2.ob_get_contents
获取一份php buffer中的数据拷贝。值得注意的是,你应该在ob_end_clean()函数调用之前调用该函数,否则ob_get_contents()返回一个空字符中。

3.ob_end_flush与ob_end_clean
这二个函数有点相似,都会关闭ouptu_buffering机制。但不同的是,ob_end_flush只是把php buffer中的数据冲(flush/send)到客户端浏览器,而ob_clean_clean将php bufeer中的数据清空(erase),但不发送给客户端浏览器。ob_end_flush调用之后,php buffer中的数据依然存在,ob_get_contents()依然可以获取php buffer中的数据拷贝。而ob_end_clean()调用之后ob_get_contents()取到的是空字符串,同时浏览器也接收不到输出,即没有任何输出。

惯用案例
常常在一些模板引擎和页面文件缓存中看到ob_start()使用。下面湿CI中加载模板的程序代码:

复制代码 代码如下:

<SPAN style="WHITE-SPACE: pre">  </SPAN>/*
   * Buffer the output
   *
   * We buffer the output for two reasons:
   * 1. Speed. You get a significant speed boost.
   * 2. So that the final rendered template can be
   * post-processed by the output class.  Why do we
   * need post processing?  For one thing, in order to
   * show the elapsed page load time.  Unless we
   * can intercept the content right before it's sent to
   * the browser and then stop the timer it won't be accurate.
   */
  ob_start();
  // If the PHP installation does not support short tags we'll
  // do a little string replacement, changing the short tags
  // to standard PHP echo statements.
  if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
  {
                        //替换短标记<?=***>
   echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
  }
  else
  {
   include($_ci_path); // include() vs include_once() allows for multiple views with the same name
  }

                //记录调试信息
  log_message('debug', 'File loaded: '.$_ci_path);
  // Return the file data if requested
  if ($_ci_return === TRUE)
  {
   $buffer = ob_get_contents();
   @ob_end_clean();
   return $buffer;
  }
  /*
   * Flush the buffer... or buff the flusher?
   *
   * In order to permit views to be nested within
   * other views, we need to flush the content back out whenever
   * we are beyond the first level of output buffering so that
   * it can be seen and included properly by the first included
   * template and any subsequent ones. Oy!
   *
   */
  if (ob_get_level() > $this->_ci_ob_level + 1)
  {
   ob_end_flush();
  }
  else
  {
                        //将模板内容添加到输出流中
   $_ci_CI->output->append_output(ob_get_contents());
                        //清除buffer
   @ob_end_clean();
  }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325815613&siteId=291194637