溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

output_buffering與ob_start怎么在php中使用

發(fā)布時間:2021-01-30 15:44:02 來源:億速云 閱讀:149 作者:Leah 欄目:開發(fā)技術(shù)

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān) output_buffering與ob_start怎么在php中使用,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

buffer

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

php output_buffering

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

復制代碼 代碼如下:


<?php
for ($i = 0; $i < 10; $i++) {
    echo $i . '<br/>';
    <a href="http://www.php.net/sleep">sleep</a>($i + 1);   //
}
?>

現(xiàn)象:不是每隔幾秒就會有間斷性輸出,而是直到響應(yīng)結(jié)束,才能看一次性看到輸出,在等待服務(wù)器腳本處理結(jié)束之前,瀏覽器界面一直保持空白。這是因為,數(shù)據(jù)量太小,php output_buffering沒有寫滿。寫數(shù)據(jù)的順序,依次是echo->php buffer->tcp buffer->browser
2.當output_buffering=0,并且輸出較少數(shù)據(jù)(少于一個buffer)

復制代碼 代碼如下:


<?php
//通過ini_set('output_buffering', 0)并不生效
//應(yīng)該編輯/etc/php.ini,設(shè)置output_buffering=0禁用output buffering機制
//ini_set('output_buffering', 0);   //徹底禁用output buffering功能
for ($i = 0; $i < 10; $i++) {
    echo $i . '<br/>';
    <a href="http://www.php.net/flush">flush</a>();  //通知操作系統(tǒng)底層,盡快把數(shù)據(jù)給客戶端瀏覽器
    <a href="http://www.php.net/sleep">sleep</a>($i + 1);   //
}
?>

現(xiàn)象:與剛才顯示并不一致,禁用了php buffering機制之后,在瀏覽器可以斷斷續(xù)續(xù)看到間斷性輸出,不必等到腳本執(zhí)行完畢才看到輸出。這是因為,數(shù)據(jù)沒有在php output_buffering中停留。寫數(shù)據(jù)的順序依次是echo->tcp buffer->browser
3.當output_buffering=4096.,輸出數(shù)據(jù)大于一個buffer,不調(diào)用ob_start()
創(chuàng)建一個4kb大小的文件
$dd if=/dev/zero of=f4096 bs=4096 count=1

復制代碼 代碼如下:


<?php
for ($i = 0; $i < 10; $i++) {
    echo <a href="http://www.php.net/file_get_contents">file_get_contents</a>('./f4096') . $i . '<br/>';
    <a href="http://www.php.net/sleep">sleep</a>($i +1);
}
?>

現(xiàn)象:響應(yīng)還沒結(jié)束(http連接沒有關(guān)閉),斷斷續(xù)續(xù)可以看到間斷性輸出,瀏覽器界面不會一直保持空白。盡管啟用了php output_buffering機制,但依然會間斷性輸出,而不是一次性輸出,是因為output_buffering空間不夠用。每寫滿一個php buffering,數(shù)據(jù)就會發(fā)送到客戶端瀏覽器。 4.當output_buffering=4096, 輸出數(shù)據(jù)大于一個tcp buffer, 調(diào)用ob_start()

復制代碼 代碼如下:


<?php
<a href="http://www.php.net/ob_start">ob_start</a>();   //開啟php buffer
for ($i = 0; $i < 10; $i++) {
    echo <a href="http://www.php.net/file_get_contents">file_get_contents</a>('./f4096') . $i . '<br/>';
    <a href="http://www.php.net/sleep">sleep</a>($i + 1);
}
<a href="http://www.php.net/ob_end_flush">ob_end_flush</a>();
?>

現(xiàn)象:直到服務(wù)端腳本處理完成,響應(yīng)結(jié)束,才看到完整輸,輸出間隔時間很短,以至你感受不到停頓。在輸出之前,瀏覽器一直保持著空白界面,等待服務(wù)端數(shù)據(jù)。這是因為,php一旦調(diào)用了ob_start()函數(shù),它會將php buffer擴展到足夠大,直到ob_end_flush函數(shù)調(diào)用或者腳本運行結(jié)速才發(fā)送php buffer中的數(shù)據(jù)到客戶端瀏覽器。
tcpdump觀察
在這里,我們通過tcpdump監(jiān)控一下tcp報文,來觀察一下使用ob_start()和沒有使用它的一個區(qū)別。
1.沒有使用ob_start()
12:30:21.499528 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 485 win 6432 12:30:21.500127 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 1:2921(2920) ack 485 win 6432 12:30:21.501000 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 2921:7301(4380) ack 485 win 6432 12:30:21.501868 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 7301:8412(1111) ack 485 win 643 12:30:24.502340 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 8412:14252(5840) ack 485 win 6432 12:30:24.503214 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 14252:15712(1460) ack 485 win 6432 12:30:24.503217 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 15712:16624(912) ack 485 win 6432   12:30:31.505934 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 16624:23924(7300) ack 485 win 6432 12:30:31.506839 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 23924:24836(912) ack 485 win 6432 12:30:42.508871 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 24836:32136(7300) ack 485 win 6432 12:30:42.509744 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 32136:33048(912) ack 485 win 6432 12:30:57.512137 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 33048:40348(7300) ack 485 win 6432 12:30:57.513016 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 40348:41260(912) ack 485 win 6432 12:31:06.513912 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 41260:41265(5) ack 485 win 6432 12:31:06.514012 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: F 41265:41265(0) ack 485 win 6432 12:31:06.514361 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 486 win 6432
2.使用了ob_start()
12:36:06.542244 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 485 win 6432 12:36:51.559128 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 1:2921(2920) ack 485 win 6432 12:36:51.559996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 2921:7301(4380) ack 485 win 6432 12:36:51.560866 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 7301:11681(4380) ack 485 win 6432 12:36:51.561612 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 11681:16061(4380) ack 485 win 6432 12:36:51.561852 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 16061:20441(4380) ack 485 win 6432 12:36:51.562479 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 20441:24821(4380) ack 485 win 6432 12:36:51.562743 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 24821:29201(4380) ack 485 win 6432 12:36:51.562996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 29201:33581(4380) ack 485 win 6432 12:36:51.563344 IP 192.168.0.8.webcache > 192.168.0.28.noagent: P 33581:35041(1460) ack 485 win 6432 12:36:51.563514 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 35041:36501(1460) ack 485 win 6432 12:36:51.563518 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 36501:37961(1460) ack 485 win 6432 12:36:51.563523 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 37961:39421(1460) ack 485 win 6432 12:36:51.563526 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 39421:40881(1460) ack 485 win 6432 12:36:51.563529 IP 192.168.0.8.webcache > 192.168.0.28.noagent: FP 40881:41233(352) ack 485 win 6432 12:36:51.570364 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 486 win 6432
通過上面的對比,我們可以看到,數(shù)據(jù)報文的時間間隔明顯不一樣。沒有使用ob_start(),時間間隔比較大,等待4秒左右就把tcp buffer中的數(shù)據(jù)發(fā)送出去了。數(shù)據(jù)沒有在php buffer中逗留過長時間,就將輸出數(shù)據(jù)發(fā)送給了客戶端瀏覽器。這是因為,很快php buffer就被寫滿了,不得不把數(shù)據(jù)發(fā)送出去。而啟用了ob_start(),則不同,發(fā)送數(shù)據(jù)包給客戶端,幾乎是同一時間發(fā)出去的。這就可以推斷,數(shù)據(jù)一直在php buffer中逗留,直到調(diào)用了ob_end_flush()才把php buffer中的數(shù)據(jù)發(fā)送給客戶端瀏覽器。

output buffering函數(shù)

1.ob_start

激活output_buffering機制。一旦激活,腳本輸出不再直接出給瀏覽器,而是先暫時寫入php buffer內(nèi)存區(qū)域。
php默認開啟output_buffering機制,只不過,通過調(diào)用ob_start()函數(shù)據(jù)output_buffering值擴展到足夠大。也可以指定$chunk_size來指定output_buffering的值。$chunk_size默認值是0,表示直到腳本運行結(jié)束,php buffer中的數(shù)據(jù)才會發(fā)送到瀏覽器。如果你設(shè)置了$chunk_size的大小,則表示只要buffer中數(shù)據(jù)長度達到了該值,就會將buffer中的數(shù)據(jù)發(fā)送給瀏覽器。
當然,你可以通過指定$ouput_callback,來處理buffer中的數(shù)據(jù)。比如函數(shù)ob_gzhandler,將buffer中的數(shù)據(jù)壓縮后再傳送給瀏覽器。

2.ob_get_contents

獲取一份php buffer中的數(shù)據(jù)拷貝。值得注意的是,你應(yīng)該在ob_end_clean()函數(shù)調(diào)用這調(diào)用該函數(shù),否則ob_get_contents()返回一個空字符中。

3.ob_end_flush與ob_end_clean

這二個函數(shù)有點相似,都會關(guān)閉ouptu_buffering機制。但不同的是,ob_end_flush只是把php buffer中的數(shù)據(jù)沖(flush/send)到客戶端瀏覽器,而ob_clean_clean將php bufeer中的數(shù)據(jù)清空(erase),但不發(fā)送給客戶端瀏覽器。ob_end_flush調(diào)用之后,php buffer中的數(shù)據(jù)依然存在,ob_get_contents()依然可以獲取php buffer中的數(shù)據(jù)拷貝。而ob_end_clean()調(diào)用之后ob_get_contents()取到的是空字符串,同時瀏覽器也接收不到輸出,即沒有任何輸出。

慣用案例

常常在一些模板引擎和頁面文件緩存中看到ob_start()使用。在知名開源項目wordpress,drupal,smarty等地方,都能夠發(fā)現(xiàn)他們的蹤影子。這里抽出drupal的應(yīng)用。
模板文件

復制代碼 代碼如下:


//@file:user-profile.tpl.php
<div>
     <ul>
          <li>username: <?php echo $user->name; ?></li>
          <li>picture:<?php echo $user->picture; ?></li>
     </ul>
</div>

//@file:template-render.php
<?php
function theme_render_template($template_file, $variables) {
  if (!<a href="http://www.php.net/is_file">is_file</a>($template_file) { return ""; }
  <a href="http://www.php.net/extract">extract</a>($variables, EXTR_SKIP);
  <a href="http://www.php.net/ob_start">ob_start</a>();
  $contents = <a href="http://www.php.net/ob_get_contents">ob_get_contents</a>();
  <a href="http://www.php.net/ob_end_clean">ob_end_clean</a>();
  return $contents;
}
?>

//@file:profile.php
<?php
$variables = <a href="http://www.php.net/array">array</a>('user' => $user);
print theme_render_template('user-profile.tpl.php', $variables);
?>

上述就是小編為大家分享的 output_buffering與ob_start怎么在php中使用了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI