PHP 輸出經過兩層緩衝:PHP 內部緩衝 → Web 伺服器緩衝 → 瀏覽器。`ob_flush()` 刷新 PHP 層,`flush()` 刷新伺服器層。**正確順序:先 `ob_flush()` 再 `flush()`**。本文詳解機制、常見誤區與實際應用。
PHP 腳本
↓ echo/print
PHP 內部輸出緩衝 (ob_start 開啟)
↓ ob_flush()
Web 伺服器緩衝 (Apache/Nginx/FastCGI)
↓ flush()
瀏覽器接收並渲染
<?php
// 關鍵:必須先開啟輸出緩衝或確保無輸出前已輸出 header
// 此處為演示,實際生產需注意 header 已發送問題
echo str_repeat(' ', 1024); // 填滿瀏覽器緩衝觸發顯示(某些瀏覽器需要)
for ($i = 0; $i < 4; $i++) {
echo "步驟 $i 完成
\n";
// 正確順序:先 PHP 層,再伺服器層
ob_flush();
flush();
sleep(1); // 模擬耗時操作
}
?>
| 錯誤現象 | 原因 | 解決 |
|---|---|---|
| 一次性全部輸出 | 順序反了(flush → ob_flush)或未開啟 ob_start | 先 ob_flush 再 flush;確保 output_buffering 受控 |
| Cannot modify header | 已有輸出(含空白、BOM)再發送 header | header 必須在任何輸出前;用 ob_start() 緩衝輸出 |
| FastCGI 緩衝導致延遲 | Nginx 預設緩衡 FastCGI 輸出 | location 設定 `fastcgi_buffering off;` |
| 壓縮模組合併輸出 | gzip/deflate 等待輸出結束再壓縮 | 關閉壓縮或用 `header('Content-Encoding: none')` |
class RealtimeOutput {
public static function init() {
@ini_set('output_buffering', 'Off');
@ini_set('zlib.output_compression', 'Off');
ob_implicit_flush(true);
ob_start();
echo str_repeat(' ', 1024); // 觸發瀏覽器渲染
}
public static function write($msg) {
echo $msg . "
\n";
ob_flush();
flush();
}
public static function end() {
ob_end_flush();
}
}
// 使用
RealtimeOutput::init();
for ($i = 0; $i < 10; $i++) {
RealtimeOutput::write("處理項目 $i");
usleep(500000);
}
RealtimeOutput::end();
掌握 `ob_flush`/`flush` 正確順序與緩衝層級配置,能實現傳統 HTTP 下的即時輸出體驗。