ob_flush和flush的區別(包括buffer,flush等)

以下內容可以瞭解更多
 

如果只想直接的話,重點看下面這段就可以了。

似乎二者的功能都是刷新輸出緩存。但在我們文章一開始的代碼中如果講fush()替換成ob_flush(),程序就再不能正確執行了。顯然,它們是有區別的,否則也手冊中直接說明其中一個是另外一個函數的別名即可了,沒必要分別說明。那麼它們的區別到底是什麼呢?

在沒有開啓緩存時,腳本輸出的內容都在服務器端處於等待輸出的狀態 ,flush()可以將等待輸出的內容立即發送到客戶端。

開啓緩存後,腳本輸出的內容存入了輸出緩存中 ,這時沒有處於等待輸出狀態的內容,你直接使用flush()不會向客戶端發出任何內容。而 ob_flush()的作用就是將本來存在輸出緩存中的內容取出來,設置爲等待輸出狀態,但不會直接發送到客戶端 ,這時你就需要先使用 ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出。




有關PHP的ob_flush()與flush()使用方法

注意:ob_flush()和flush()這兩個函數一般要一起使用,順序是先ob_flush(),然後flush(),它們的作用是刷新緩衝區。
這裏具體的說下什麼時候要用到刷新緩衝區和爲什麼要刷新緩衝區。

一、什麼時候要刷新緩衝區

當程序中用到file_get_contents()和file_put_contens()這兩個函數時,或程序中執行類似的“讀寫”功能或向瀏覽器執行輸出操作時,會用到ob_flush()和flush()來刷新緩衝區。

二、爲什麼要刷新緩衝區

用file_get_contents()和file_put_content()爲例進行講解。

file_get_contents()和file_put_conents()這兩個函數分別執行讀取數據和寫入數據操作,數據是先被讀到內存中然後在寫入文件中的,因爲讀取的速度比寫入的速度要快,所以當你的數據被讀完的時候不代表數據也寫入完畢,這個時候多讀的內容就會被暫時放到緩衝區中(內存),在這裏需要強調一下,其實數據讀取和寫入是兩個非常快的動作哦。

還用一種解釋(當程序向瀏覽器執行輸出操作時),個別web服務器程序,特別是Win32下的web服務器程序,在發送結果到瀏覽器之前,仍然會緩存腳本的輸出,直到程序結束爲止。如果你不想讓程序執行完畢才向瀏器輸出,那麼你也可以用到ob_flush()和flush()來刷新緩存。

其實,flush()還有一種用途,就是在沒結束程序之前就進行輸出,即一個循環還沒結束就可以把部分結果輸出到瀏覽器上,這個效果很類似 ajax的異步傳輸效果。

深入理解ob_flush和flush的區別

ob_flush/flush在手冊中的描述, 都是刷新輸出緩衝區, 並且還需要配套使用, 所以會導致很多人迷惑… 

其實, 他們倆的操作對象不同, 有些情況下, flush根本不做什麼事情.. 

ob_*系列函數, 是操作php本身的輸出緩衝區. 

所以, ob_flush是刷新PHP自身的緩衝區. 

而flush, 嚴格來講, 這個只有在PHP做爲apache的Module(handler或者filter)安裝的時候, 纔有實際作用. 它是刷新WebServer(可以認爲特指apache)的緩衝區. 

在apache module的sapi下, flush會通過調用sapi_module的flush成員函數指針, 間接的調用apache的api: ap_rflush刷新apache的輸出緩衝區, 當然手冊中也說了, 有一些apache的其他模塊, 可能會改變這個動作的結果.. 

有些Apache的模塊,比如mod_gzip,可能自己進行輸出緩存,這將導致flush()函數產生的結果不會立即被髮送到客戶端瀏覽器。 

甚至瀏覽器也會在顯示之前,緩存接收到的內容。例如 Netscape瀏覽器會在接受到換行或 html 標記的開頭之前緩存內容,並且在接受到 </table> 標記之前,不會顯示出整個表格。 

一些版本的 Microsoft Internet Explorer 只有當接受到的256個字節以後纔開始顯示該頁面,所以必須發送一些額外的空格來讓這些瀏覽器顯示頁面內容所以, 正確使用倆者的順序是. 先ob_flush, 然後flush, 

當然, 在其他sapi下, 不調用flush也可以, 只不過爲了保證你代碼的可移植性, 建議配套使用.

 

 

buffer ---- flush()


buffer是一個內存地址空間,Linux系統默認大小一般爲4096(1kb),即一個內存頁。主要用於存儲速度不同步的設備或者優先級不同的 設備之間傳辦理數據的區域。通過buffer,可以使進程這間的相互等待變少。這裏說一個通俗一點的例子,你打開文本編輯器編輯一個文件的時候,你每輸入 一個字符,操作系統並不會立即把這個字符直接寫入到磁盤,而是先寫入到buffer,當寫滿了一個buffer的時候,纔會把buffer中的數據寫入磁 盤,當然當調用內核函數flush()的時候,強制要求把buffer中的髒數據寫回磁盤。
同樣的道理,當執行echo,print的時候,輸出並沒有立即通過tcp傳給客戶端瀏覽器顯示, 而是將數據寫入php buffer。php output_buffering機制,意味在tcp buffer之前,建立了一新的隊列,數據必須經過該隊列。當一個php buffer寫滿的時候,腳本進程會將php buffer中的輸出數據交給系統內核交由tcp傳給瀏覽器顯示。所以,數據會依次寫到這幾個地方echo/pring -> php buffer -> tcp buffer -> browser

php output_buffering --- ob_flush()

默認情況下,php buffer是開啓的,而且該buffer默認值是4096,即1kb。你可以通過在php.ini配置文件中找到output_buffering配置.當echo,print等輸出用戶數據的時候,輸出數據都會寫入到php output_buffering中,直到output_buffering寫滿,會將這些數據通過tcp傳送給瀏覽器顯示。你也可以通過 ob_start()手動激活php output_buffering機制,使得即便輸出超過了1kb數據,也不真的把數據交給tcp傳給瀏覽器,因爲ob_start()將php buffer空間設置到了足夠大 。只有直到腳本結束,或者調用ob_end_flush函數,纔會把數據發送給客戶端瀏覽器。

這兩個函數的使用怕是很多人最迷惑的一個問題,手冊上對兩個函數的解釋也語焉不詳,沒有明確的指出它們的區別,似乎二者的功能都是刷新輸出緩存。但在我們文章一開始的代碼中如果講fush()替換成ob_flush(),程序就再不能正確執行了。顯然,它們是有區別的,否則也手冊中直接說明其中一個是另外一個函數的別名即可了,沒必要分別說明。那麼它們的區別到底是什麼呢?

在沒有開啓緩存時,腳本輸出的內容都在服務器端處於等待輸出的狀態 ,flush()可以將等待輸出的內容立即發送到客戶端。

開啓緩存後,腳本輸出的內容存入了輸出緩存中 ,這時沒有處於等待輸出狀態的內容,你直接使用flush()不會向客戶端發出任何內容。而 ob_flush()的作用就是將本來存在輸出緩存中的內容取出來,設置爲等待輸出狀態,但不會直接發送到客戶端 ,這時你就需要先使用 ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出。

一. flush和ob_flush的正確順序,正確應是,先ob_flush再flush,如下: 
ob_flush();
flush();
如果Web服務器的操作系統是windows系統,那順序顛倒或者不使用ob_flush()也不會出現問題。[有待求證 ] 但是在Linux系統上就無法刷新輸出緩衝。

output buffering函數
1.bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
激活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中的數據壓縮後再傳送給瀏覽器。
第三個參數:是否擦除緩存,可選,默認是true,如果設置爲false,則在腳本執行結束前,緩存都不會被清除。
2.ob_get_contents
獲取一份php buffer中的數據拷貝。值得注意的是,你應該在ob_end_clean()函數調用前調用該函數,否則ob_get_contents()返回一個空字符中。

可以使用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函數,這點似乎不常遇到,遇到的時候記得去查手冊吧。

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_flush()調用之後 ob_get_contents()取到的是空字符串,同時瀏覽器也接收不到輸出,即沒有任何輸出。

可以使用ob_get_contents()以字符串形式獲取服務端緩存的數據,使用ob_end_flush()則會輸出被緩存起來的數據,並關閉緩存。
而使用ob_end_clean()則會靜默的清除服務端緩存的數據,而不會有任何數據或其他行爲。

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