注意修改php.ini之後需要重新啟動apache服務行!
for($i=0;$i<10;$i++) { echo $i.'<br />'; flush(); sleep(1); }
有了解PHP快取輸出控制函數的朋友肯定對上面這段程式碼很熟悉,它想實現的效果是每個1秒輸出1個數字,完成全部輸出需要10秒,不過實際執行中你會發現奇怪的現象,有些人或者有些時候它的表現如你所願,而有些人或者有些時候卻是10秒後才會一次性輸出10個數字。我曾經為此抓狂不已,有朋友留言說這個情況往往是因為IE的緩存必須達到256個字符才會輸出,可實際上我之前也考慮到IE的情況,可依舊會有時靈時不靈的情況。今天仔細讀過手冊才明白,這些不可預料的現像是有它的理由的。
原來php.ini中有兩個關鍵參數會影響到php的快取輸出控制:
參數1:output_buffering :on/off 或整數 。設定為on時,將在所有腳本中使用輸出快取控制,不限制快取的大小。而設定為整數時,如output_buffering=4096,當快取資料達到 4096位元組時會自動輸出刷新快取。而這個參數的差異正是導致以上程式碼在不同時候執行結果不同的原因。當output_buffering關閉時,腳本所有的輸出(echo)都會即時傳送到客戶端,執行上面程式碼時就是每秒輸出一個數字。而開啟output_buffering後,輸出內容就會先緩存在服務端,直到腳本結束時才一起傳送給客戶端。
參數2:implicit_flush:on/off。設定ON意味著,當腳本有輸出時,自動立即傳送到客戶端。相當於在echo後自動加flush()。
php快取輸出控制的相關函數:
ob_start()
第一個參數:回調函數,可選。在快取輸出前可以過濾或其他處理。最常見的用法是ob_start('ob_gzhandler'),也就是對快取的資料進行gzip壓縮後再傳送給客戶端。
第二個參數:快取區塊的大小,可選。如果被快取的內容達到或操作快取區塊的大小,快取會自動輸出。預設值是0,指不限定大小,快取到結束為止。還有個特殊值1,代表chunk_size=4096。
第三個參數:是否擦除緩存,可選,預設為true,如果設定為false,則在腳本執行結束前,快取都不會被清除。
可以使用ob_get_contents()以字串形式取得服務端快取的數據,使用ob_end_flush()則會輸出被快取起來的數據,並關閉快取。
而使用ob_end_clean()則會靜默的清除服務端快取的數據,而不會有任何數據或其他行為。
服務端的快取是堆疊起來的,也就是說你在開啟了ob_start()後,關閉之前,在其內部還可以開啟另外一個快取 ob_start()。不過你也要務必確保關閉快取的操作和開啟快取的操作數量一樣多。
ob_start()可以指定一個回呼函數來處理快取數據,如果一個ob_start()內部嵌套了另一個
ob_start(),我們假定,外層的ob_start(),編號是A,內層的ob_start()編號是B,它們各自製定了一個回呼函數分別是functionA和functionB,那麼在快取B中的資料輸出時,它會先輩funcitonB回呼函數處理,再交給外層的functionA回呼函數處理,之後才能輸出到客戶端。
另外,手冊說,對於某些web伺服器,例如apache,在使用回呼函數有可能會改變程式目前的工作目錄,解決方法是在回呼函數中自行手動把工作目錄修改回來,用chdir函數,這點似乎不常遇到,遇到的時候記得去查手冊吧。
flush()和ob_flush()
這兩個函數的使用怕是許多人最迷惑的一個問題,手冊上對兩個函數的解釋也語焉不詳,沒有明確的指出它們的差別,似乎二者的功能都是刷新輸出快取。但在我們文章一開始的程式碼中如果講fush()替換成 ob_flush(),程式就再不能正確執行了。顯然,它們是有區別的,否則也手冊中直接說明其中一個是另一個函數的別名即可了,沒必要分別說明。那麼它們的差別到底是什麼呢?
反复研究了手册的说明,参考了手册中一些人的留言,自己琢磨应该是这样的:
在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端。
开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出。
也就是说本文开头的脚本,可以根据缓存开启与否,有如下几种不同的写法:
注:以下代码都未考虑IE缓存必须大于256字节才输出的问题,如在IE下测试,请在代码开始加一句:“echo str_repeat('',256)”
写法1:
output_buffering = off implicit_flush=off for($i=0;$i<10;$i++) { echo $i.'<br />'; flush(); sleep(1); }
写法2:
output_buffering = on implicit_flush=off for($i=0;$i<10;$i++) { echo $i.'<br />'; ob_flush(); flush(); sleep(1); }
写法3:
output_buffering = off implicit_flush=off ob_start(); for($i=0;$i<10;$i++) { echo $i.'<br />'; ob_flush(); flush(); sleep(1); }
写法4:
output_buffering = on implicit_flush=off ob_end_flush(); for($i=0;$i<10;$i++) { echo $i.'<br />'; flush(); sleep(1); }
写法5:
output_buffering = on implicit_flush=off ob_end_clean(); for($i=0;$i<10;$i++) { echo $i.'<br />'; flush(); sleep(1); }
写法6:
output_buffering = on; implicit_flush=on ob_end_clean(); // 或者ob_end_flush(); for($i=0;$i<10;$i++) { echo $i.'<br />'; sleep(1); }
写法7:
output_buffering = on; implicit_flush=on ob_end_clean(); // 或者ob_end_flush(); for($i=0;$i<10;$i++) { echo $i.'<br />'; flush(); sleep(1); }
写法8:
output_buffering = off implicit_flush=on for($i=0;$i<10;$i++) { echo $i.'<br />'; sleep(1); }
以上是php輸出快取函數 ob_start,flush,ob_flush用法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!