什麼是緩衝區(buffer)?
簡單而言,緩衝區的作用就是,把輸入或輸出的內容先放進內存,而不顯示或讀取。其實緩衝區最本質的功能就是,協調高速CPU和相對緩慢的IO設備(磁碟等)的運作。
PHP在執行的時候,在什麼地方有用到緩衝區?
想要了解PHP的緩衝區,就要知道執行PHP的時候,緩衝區被設定到了什麼地方。
當執行PHP的時候,如果碰到了echo print_r之類的會輸出資料的程式碼,PHP就會將要輸出的資料放到PHP本身的緩衝區,等待輸出。
當PHP本身的緩衝區接到指令,指示要輸出緩衝區的內容時,將會把緩衝區內的數據輸出到apache上,apache接受到PHP輸出的數據,然後再把該資料存在到apache自身的緩衝區內,等到輸出。
當apache接受到指令,只是要輸出緩衝區的內容時,會把緩衝區的內容輸出,回到瀏覽器。
步驟:執行php---->(碰到echo,print_r之類輸出)將輸出的資料放到php本身的緩衝區,等待輸出---->(接收輸出緩衝區內容)資料輸出到apache上,存入apache本身的緩衝區---->(接收輸出指定)緩衝區內容輸出,回到瀏覽器
echo、print => ; php output_buffering => webServer buffer => browser buff => browser display
即:腳本輸出=> php的緩衝區設定=>系統的緩衝區設定(apache、 nginx) => 瀏覽器的緩衝區設定=> 顯示給使用者
#由此可見,PHP要輸出資料的時候,將會經過兩個緩衝區(先是自身的,然後是apache的),再返回到瀏覽器。
相關推薦:《PHP入門教學》
#緩衝區在PHP中扮演什麼角色?
1.最常見的就是在使用header函數之前,就已經輸出了某些數據,這樣會導致某些錯誤,例如Cannot modify header information – headers already sent by;
echo "this is test"; header("LOCATION http://www.baidu.com");
出現這個錯誤的原因是,在header之前已經輸出了某些數據,而輸出這些數據的同時,apache將會同時發送一個響應狀態到瀏覽器上(既然有輸出,即這個請求是有效的),而其後你又再次使用header函數。
發送http頭,則會回傳這個錯誤,錯誤的意思是:HTTP頭已經發送出去了,你不能對他再做修改。
為什麼使用緩衝區可以避免這個錯誤呢?
因為header函數是不受緩衝區影響的,當一碰到header函數的時候,PHP馬上執行apache發送這一個http頭都瀏覽器。
而輸出的資料PHP開啟輸出緩衝區後,這些資料將會存放在緩衝區,等待輸出。這樣就可以避免了之前發生的錯誤。
2.透過PHP寫檔案下載程式的時候。 ((實例篇)PHP實作HTTP斷點續傳的方法的原理)
為了讓文件下載更安全,同時提高更多的可控性,很多朋友都喜歡用PHP寫文件下載頁面。其原理很簡單,就是透過fwrite把文件內容讀出並顯示,然後透過header來發送HTTP頭,讓瀏覽器知道這是一個附件,這樣就可以達到提供下載的效果。
如果用上面的辦法提供下載頁面,會碰到一個效率問題,如果一個檔案很大,假設為100M,那麼在不開啟緩衝區輸出的情況下,必須要把100M資料全部讀出,然後一次返回到頁面上,如果這樣做,用戶將會在所有數據讀完之後才會得到回應,降低了用戶體驗感。
如果開啟了輸出緩衝區,當PHP程式讀完檔案的某一段,然後馬上輸出到apache,然後讓apache馬上回到瀏覽器,這樣就可以減少使用者等待時間。那後面的數據怎麼辦呢?我們可以寫一個while循環,一直一段一段地讀取文件每讀一段,就馬上輸出,直到把文件全部輸出為止,這樣瀏覽器就可以持續地接受到數據,而不必等到所有文件讀取完畢。另外,該做法也解決了另外一個很嚴重的問題。
例如一個檔案是100M,如果不開啟緩衝區的情況下,則需要把100M檔案全部讀入內存,然後再輸出。但是,如果PHP程式做了記憶體限制呢?為了確保伺服器的穩定,管理員通常會把PHP的執行記憶體設一個限制(透過php.ini總的memory_limit,其預設值是8M),也就是每個PHP程式所使用的記憶體就不能使用超過這個值的記憶體。假設該值為8M,而要讀入的檔案是100M,根本就沒有足夠的記憶體來讀入該檔案。這時候,我們就需要用到上面的辦法來解決這個問題,每次只讀某一段,這樣就可以避免了記憶體的限制。
3.静态文件缓存
现在很多公司有这么一个需求,就是某一个页面在第一次访问的时候,会执行PHP,然后把显示的内容返回到浏览器,同时需要把这次显示的内容保存到服务器上,这样下次访问的时候,就直接把保存在服务器上的文件直接显示,而不需要通过PHP来做操作这就是所谓的”静态页面缓存”。那怎么样才能做到把内容返回到浏览器的同时把数据保存到服务器上呢?这就要用到输出缓冲区了。
ob_start(); echo 'aaa'; $string = ob_get_contents(); file_put_contents('a.html', $string); ob_flush(); flush();
与输出缓冲区有关的配置
在PHP.INI中,有两个跟缓冲区紧密相关的配置项
1.output_buffering
该配置直接影响的是php本身的缓冲区,有3种配置参数:on/off/xK(x为某个整型数值);
on - 开启缓冲区
off - 关闭缓冲区
256k - 开启缓冲区,而且当缓冲区的内容超过256k的时候,自动刷新缓冲区(把数据发送到apache);
2.implicit_flush
该配置直接影响apache的缓冲区,有2种配置参数:on/off
on - 自动刷新apache缓冲区,也就是当php发送数据到apache的缓冲区的时候,不需要等待其他指令,直接就把输出返回到浏览器。
off - 不自动刷新apache缓冲区,接受到数据后,等待刷新指令。
与缓冲区有关的函数
1.ob_implicit_flush
作用和implicit_flush一样,是否自动刷新apache的缓冲区。
2.flush
作用是发送指令到apache,让apache刷新自身的输出缓冲区。
3.ob_start
打开输出缓冲区,无论php.ini的文件如何配置,如果使用该函数,即使output_buffering设置成off,也会打开输出缓冲区
ob_start函数还接受一个参数,该参数是一个函数的回调,意思是在输入缓冲区内容之前,需要使用调用传递进来的参数把缓冲区的内容处理一次,再放入缓冲区内。
4.ob_flush
指示php本身刷新自身的缓冲区,把数据发送到apache。
5.ob_clean
清除php缓冲区里面的内容。
6.ob_end_clean
清除php缓冲区内的内容,并且关闭输出缓冲区。
7.ob_end_flush
把php自身的缓冲区里的内容发送到apache,并把清除自身缓冲区内的内容。
8.ob_get_clean
获取缓冲区的内容之后,清除缓冲区。
9.ob_get_contents
获取输出缓冲区里的内容。
10.ob_get_flush
获取缓冲区里的内容,并且把这些内容发送到apache。
11.ob_get_length
获取缓冲区里内容的长度。
12.ob_list_handlers
获取运行ob_start时,所回调的函数名称,例如:
ob_start(‘ob_gzhandler’); print_r(ob_list_handlers);
将打印出ob_gzhandler。
13.ob_gzhandler
该函数的作用是作为ob_start的回调参数,在缓冲区刷新之前,会调用该函数对数据进行到底gzip或者deflate压缩。这个函数需要zlib扩展的支持。
使用缓冲区的相关内容
1.ob_flush和flush的次序关系。上面的分析可以看出,ob_flush是和php自身相关的,而flush操作的是apache的缓冲区,所有我们在使用这两个函数的时候,需要先执行ob_flush,再执行flush,因为我们需要先把数据从PHP上发送到apache,然后再由apache返回到浏览器。如果php还没有把数据刷新到apache,就调用了flush,则apache无任何数据返回到浏览器。
2.有的浏览器,如果接受到的字符太少,则不会把数据显示出来,例如老版的IE(必须要大于256k才显示)。这样就会造成一个疑问,明明在php和apache都进行了刷新缓冲区的操作,但是浏览器就是没有出现自己想要的数据,也许就是这个原因造成的。所以才测试的时候,可以在输出数据的后面加上多个空格,以填满数据,确定不会浏览器造成这类诡异的问题。
3.有些webserver,他自身的输出缓冲区会有一些限制,比如nginx,他有一个配置fastcgi_buffer_size 4k,就是是表明,当自身的输出缓冲区的内容达到4K才会刷新,所以为了保证内容的数据,可以添加以下代码,保证内容长度。
<?php echo str_repeat(" ",4096); ?>
4.在apache中,如果你开启了mod_gzip的压缩模块,这样可能会导致你的flush函数刷新不成功,其原因是mod_gzip有自己的输出缓冲区,当php执行了flush函数,指示apache刷新输出缓冲区,但是内容需要压缩,apache就把内容输出到自身的mod_gzip模块,mod_gzip也有自身的输出缓冲区,他也不会马上输出,所以造成了内容不能马上输出。为了改善这个情况,可以关闭mod_gzip模块,或者在httpd.conf增加以下内容,以禁止压缩。
以上是php裡緩衝區的作用是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!