php緩衝區總結

一、背景

我們先來看一段代碼。

<?php
for ($i=10; $i>0; $i--){
    echo $i;
    flush();
    sleep(1);
}
?>

按照php手冊裏的說法該函數將當前爲止程序的所有輸出發送到用戶的瀏覽器。

上面的這段代碼,應該隔一秒鐘輸出一次$i。但是實際中卻不一定是這樣。有可能是等了10秒鐘後,所有的輸出同時呈現出來。好,我們來改一下這段代碼,改成如下:

<?php
ob_end_clean();//修改部分
for ($i=10; $i>0; $i--){
    echo $i;
    flush();
    sleep(1);
}
?>

 加了這一句ob_end_clean();,居然就OK了。實際上,我們把ob_end_clean()換成ob_end_flush()也一樣OK。再改成如下所示:

<?php
for ($i=10; $i>0; $i--){
    echo $i;
    ob_flush();//修改部分
    flush();
    sleep(1);
}
?>

 運行一下,是不是發現$i也隔一秒輸出一次了?這是爲什麼呢?

 

二、問題答疑

      打開php.ini,搜索output_buffering,我們會看到類似這樣的設置 output_buffering = 4096。正如它的名字output_buffering一樣,這個設置的作用就是把輸出緩衝一下,緩衝大小爲4096bytes.

     在我們的第一段代碼裏,之所以沒有按預期的輸出,正是因爲這個output_buffering把那些輸出都緩衝了。沒達到4096bytes或者腳本結束,輸出是不會被髮送出去的。

     而第二段代碼中的ob_end_clean()和ob_end_flush()的作用,就是終止緩衝。這樣就不用等到有4096bytes的緩衝之後才被髮送出去了。

    第三段代碼中,用了一句ob_flush(),它的作用就是把緩衝的數據發送出去,但是並不會終止緩衝,所以它必須在每次flush()前使用。

    如果不想使用ob_end_clean(),ob_end_flush()和ob_flush(),我們就必須把php.ini裏output_buffering設得足夠小,例如設爲0。需要注意的是,如果你打算在腳本中使用ini_set(“output_buffering”,”0″)來設置,那麼請停下來吧,這種方法是不行的。因爲在腳本一開始的時候,緩衝設置就已經被載入,然後緩衝就開始了。

   可能你會問了,既然ob_flush()是把緩衝的數據發送出去,那麼爲什麼還需要用flush()???直接用下面這段代碼不行嗎??

<?php
for ($i=10; $i>0; $i--){
    echo $i;
    ob_flush();
    sleep(1);
}
?>

     請注意ob_flush()和flush()的區別。前者是把數據從PHP的緩衝中釋放出來,後者是把不在緩衝中的或者說是被釋放出來的數據發送到瀏覽器。所以當緩衝存在的時候,我們必須ob_flush()和flush()同時使用。

    那是不是flush()在這裏就是不可缺少的呢?不是的,我們還有另外一種方法,使得當有數據輸出的時候,馬上被髮送到瀏覽器。下面這兩段代碼就是不需要使用flush()了。(當你把output_buffering設爲0的時候,連ob_flush()和ob_end_clean()都不需要了)

<?php
ob_implicit_flush(true);
for ($i=10; $i>0; $i--){
    echo $i;
    ob_flush(); //如果ob函數打開的情況下
    sleep(1);
}
?>

 

<?php
ob_end_clean();
ob_implicit_flush(true);
for ($i=10; $i>0; $i--)
{
    echo $i;
    sleep(1);
}
?>

請注意看上面的ob_implicit_flush(true),這個函數強制每當有輸出的時候,即刻把輸出發送到瀏覽器。這樣就不需要每次輸出(echo)後,都用flush()來發送到瀏覽器了。

 

綜上所述:可能在某些瀏覽器中不成立。因爲瀏覽器也有自己的規則。我是Firefox1.5,IE6,opera8.5來測試的。其中opera就不能正常輸出,因爲它有一個規則,就是不遇到一個HTML標籤,就絕對不輸出,除非到腳本結束。而FireFox和IE還算比較正常的。

 

最後附上一段非常有趣的代碼,作者爲PuTTYshell。在一個腳本週期裏,每次輸出,都會把前一次的輸出覆蓋掉。

 

以下代碼只在firefox下可用,其他瀏覽器並不支持multipart/x-mixed-replace的Content-Type.

<?php
  header('Content-type: multipart/x-mixed-replace;boundary=endofsection');
  print "\n--endofsection\n";

  $pmt = array("-", "\\", "|", "/" );
  for( $i = 0; $i <10; $i ++ ){
     sleep(1);
     print "Content-type: text/plain\n\n";
     print "Part $i\t".$pmt[$i % 4];
     print "--endofsection\n";
     ob_flush();
     flush();
  }
  print "Content-type: text/plain\n\n";
  print "The end\n";
  print "--endofsection--\n";
?>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章