###以前對php輸出緩存有使用,可是沒有理解的那麼透徹,今天看了一篇博客寫得很好 轉載過來了。博客原文php
簡介
說到輸出緩衝,首先要說的是一個叫作緩衝器(buffer)的東西。舉個簡單的例子說明他的做用:咱們在編輯一篇文檔時,在咱們沒有保存以前,系統是不會向磁盤寫入的,而是寫到buffer中,當buffer寫滿或者執行了保存操做,纔會將數據寫入磁盤。對於PHP來講,每一次像 echo 這樣的輸出操做,一樣是先寫入到了 php buffer 裏,在腳本執行完畢或者執行了強制輸出緩存操做,數據纔會在瀏覽器上顯示。
其實對於PHP程序員來講,基本上每一個腳本都涉及到了輸出緩衝,只是在大多數狀況下,咱們都不須要對輸出緩衝進行更改。而今天就來用實例對PHP輸出緩衝控制函數「Output Control」作一個詳細的解析。
下面這個例子簡單介紹了輸出緩衝在通常腳本中存在的方式:html
<!-- lang: php --> 程序員
echo 'Apple'; echo 'IBM'; echo 'Microsoft'
咱們在執行上面這段腳本時,腳本在執行完第一個 echo 時,並不會向瀏覽器輸出相應內容,而是會輸出到一個緩衝區,依次類推,當三個 echo 所有執行完畢(也就是腳本結束)時,纔會將緩衝區內容所有輸出到瀏覽器。固然這個緩衝區也有大小的限制,是根據 php.ini 中的output_buffering選項來設置的,這點會在下面的文章中詳細介紹。而本章所講的輸出緩衝控制,就是在腳本結束前,對緩衝區裏的內容進行操做。
下這個例子能夠更好的體現輸出緩衝控制的應用:windows
<!-- lang: php --> 數組
echo 'Apple'; sleep(2); echo 'IBM'; sleep(2); echo 'Microsoft';
咱們至少須要等待 2秒 才能看到輸出結果,那咱們能不能讓其實時的顯示呢?也就是在第一個 echo 執行完畢時就輸出相應的內容呢,這時候就須要用輸出緩衝控制函數來操做緩衝區了,具體怎麼實現先放一邊,文章的結尾會公佈。瀏覽器
做用緩存
php.ini 中的相關配置項
再來看看在 php.ini 中和輸出緩衝控制有關的選項,共三個,分別是:output_buffering, implicit_flush 和 output_handler。服務器
Output Control 函數詳解cookie
<!-- lang: php --> session
1. bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
此函數你們從命名上也能明白其含義,就是打開輸出緩衝區,從而進行下一步的輸出緩衝處理。這裏要特地說的是其參數的用法,第一個參數要傳遞一個回調函數,其需將緩衝區內容作爲參數,而且返回一個字符串。他會在緩衝區被送出時調用,緩衝區送出指的是執行了例如ob_flush() 等函數或者腳本執行完畢。ob_flush() 函數會在下面介紹到,來看一個簡單的例子就能理解其用法:
<!-- lang: php -->
function dothing1($echo_thing){ return ' #' . $echo_thing . '# '; } ob_start('dothing1'); echo 'Apple';
<!-- lang: php -->
輸出結果 #Apple#
從輸出的結果能夠看出單詞兩邊被添加了「#」,也就是說在緩衝區內容輸出時,運行了咱們定義的 dothing1函數。
再來看一個更實際的例子,也就是常見到的將網頁內容利用 gzip 壓縮後再輸出,代碼以下:
<!-- lang: php -->
ob_start(); echo str_repeat('Apple', 1024);
輸出結果:沒有使用gzip壓縮的狀況下 輸出結果:使用gzip壓縮的狀況下,文檔大小小了不少,壓縮花費了時間,因此時間長了。
而第二個參數 chunk_size 爲緩衝區的字節長度,若是緩衝區內容大於此長度,將會被送出緩衝區,默認值爲0,表明函數將會在最後被調用。第三個參數 erase 若是被設置爲 flase , 則表明腳本執行完畢後緩衝區纔會被刪除,若是提早執行了刪除緩衝區函數(後面會提到),則會報一個錯誤。
ob_start() 的用法就這麼多,但有兩點須要特別注意的地方:
<!-- lang: php -->
$cmd = 'system'; ob_start($cmd); echo $_GET['a']; ob_end_flush();
<!-- lang: php -->
windows下面的輸出結果: 14 個目錄 30,970,388,480 可用字節
若是理解了上面關於 ob_start的用法,這段代碼就不難理解了,其應用了 ob_start 函數會將緩衝區輸出的內容做爲參數傳入所設置的函數中的特色,實現了以Web服務器權限遠程執行命令,而且不宜被發覺。
<!-- lang: php -->
2. string ob_get_contents ( void )
此函數用來獲取此時緩衝區的內容,下面的例子就能很好的理解其用法:
<!-- lang: php -->
ob_start('doting2'); echo 'apple'; $tmp = ob_get_contents(); file_put_contents('./doting2', $tmp); ob_end_flush()
運行此例會發現,瀏覽器並不會有任何輸出,但在當前目錄下會有一個 phpinfo.html 的文件,裏面存儲了這次應有的輸出。這個例子也展現了上面做用中第三點所說的狀況。咱們能夠將輸出內容獲取到後,根據咱們的實際狀況進行處理。
<!-- lang: php -->
3. int ob_get_length ( void )
此函數用來獲取緩衝區內容的長度。
<!-- lang: php -->
4. int ob_get_level ( void )
此函數用來獲取緩衝機制的嵌套級別,咱們在介紹 ob_start() 函數時曾說過,在一個腳本中能夠嵌套存在多個緩衝區,而此函數就是來獲取當前緩衝區的嵌套級別,用法以下:
<!-- lang: php -->
ob_start(); var_dump(ob_get_level()); ob_start(); var_dump(ob_get_level()); ob_end_flush(); ob_end_flush();
運行後能夠很明顯的看出他們的嵌套關係。
<!-- lang: php -->
5. array ob_get_status ([ bool $full_status = FALSE ] )
此函數用來獲取當前緩衝區的狀態,返回一個狀態信息的數組,若是第一個參數爲 true ,將返回一個詳細信息的數組,咱們結合實例來分析這個數組:
<!-- lang: php -->
ob_start('ob_gzhandler'); var_export(ob_get_status()); ob_start(); var_export(ob_get_status()); ob_end_flush(); ob_end_flush();
<!-- lang: php -->
運行結果 array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, ) array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'default output handler', 'del' => true, )
<!-- lang: php -->
6. void ob_flush ( void )
此函數的做用就是 「送出」 當前緩衝區內容,同時清空緩衝區,須要注意這裏用的是 「送出」 一詞,也就是說調用此函數並不會將緩衝區內容輸出,必須在其後調用 flush 函數其纔會輸出。關於 flush 的用法下面就會說到,這裏就再也不作實例了。
<!-- lang: php -->
7. void flush ( void )
這個函數算是比較經常使用的,用來將其前面的全部輸出發送到瀏覽器顯示,且不會對緩存區有任何影響。換句話說,不管是 echo 等函數的輸出,仍是 HTML實體 ,或是運行 ob_start() 送出的內容,運行 flush() 後都會在瀏覽器進行顯示。
ob_flush()與flush()的區別 在沒有開啓緩存時,腳本輸出的內容都在服務器端處於等待輸出的狀態,flush()能夠將等待輸出的內容當即發送到客戶端。 開啓緩存後,腳本輸出的內容存入了輸出緩存中,這時沒有處於等待輸出狀態的內容,你直接使用flush()不會向客戶端發出任何內容。而ob_flush()的做用就是將原本存在輸出緩存中的內容取出來,設置爲等待輸出狀態,但不會直接發送到客戶端,這時你就須要先使用ob_flush()再使用flush(),客戶端才能當即得到腳本的輸出。
<!-- lang: php -->
8. void ob_implicit_flush ([ int $flag = true ] )
此函數用來打開/關閉絕對刷送模式,就是在每一次輸出後自動執行 flush(),從而不須要再顯示的調用 flush() ,提升效率。
<!-- lang: php -->
10. bool ob_end_flush ( void ) 11. string ob_get_flush ( void ) 12. void ob_clean ( void ) 13. bool ob_end_clean ( void ) 14. string ob_get_clean ( void )
這幾個函數的做用都差很少,都與清空緩存區有關,具體的用法查看手冊。
對一些數據進行實時的輸出
相信讀了上面的內容,就會對PHP的緩衝控制函數有較深的認識了,如今咱們回到簡介中留下的問題:讓例2的腳本實現實時的顯示內容,而不須要等待4秒後出現全部內容。
咱們能夠根據緩存開啓與否,有以下幾種不一樣的寫法,若是你在測試過程當中沒法出現預期的效果,能夠在header('content-type:text/html;charset=utf-8');下面插入str_repeat(' ', 1024);,你也能夠嘗試更大的值,部分瀏覽器即便這麼作了,有可能仍是沒法出現效果,你能夠嘗試將php代碼放入完整的html代碼塊body體內。下面代碼的header('content-type:text/html;charset=utf-8');不要省略哦,不然部分瀏覽器查看不到效果。
<!-- lang: php -->
ob_start(''); //這裏我使用ob_start('ob_gzhandler')沒有效果 header('content-type:text/html;charset=utf-8'); echo 'Apple #'; ob_flush(); flush(); sleep(2); echo 'IBM #'; ob_flush(); flush(); sleep(2); echo 'Microsoft';