PHP模板引擎(Twig/Blade)默认不兼容实时输出,因其将模板编译为PHP代码并在ob_start()内执行,输出被锁在内层缓冲区,直至渲染结束才发出;强行flush会导致空白页、截断或headers已发送错误。
PHP 实时输出(如 flush() + ob_flush())和主流模板引擎(Twig、Blade、Smarty)**默认不兼容**,因为它们普遍依赖完整的输出缓冲(OB)生命周期,会拦截并延迟最终响应。强行实时输出容易导致空白页、截断、HTTP 头已发送错误(headers already sent),或模板变量未解析就刷出。
Twig 和 Blade 都在渲染阶段将整个模板编译为 PHP 代码,并在 ob_start() 内执行 —— 输出被锁在最内层缓冲区里,直到 ob 或脚本结束才真正发出。你调用 
flush() 时,底层可能根本没数据可送,或者只刷出 HTTP 头而没内容。
$twig->render('template.twig', $data) → 返回字符串,不是流式写入view('page') 同理,返回完整 HTML 字符串,不支持分块回调ob_implicit_flush(true),也无法绕过模板引擎自身的 OB 层级嵌套若必须边生成边输出(如长耗时报表、SSE、进度流),放弃 Twig/Blade,改用轻量可控的原生 PHP 模板方式:
include 'template.php'
echo + ob_flush() + flush(),确保每段逻辑后主动刷出header('Content-Type: text/html; charset=utf-8')、header('X-Accel-Buffering: no')(Nginx)ini_set('zlib.output_compression', 'Off'),否则 flush() 无效示例片段:
开始处理...
步骤 {$i} 完成"; flush(); ob_flush(); sleep(1); } ?>
标准模板引擎难改造,但可考虑以下更底层或专用方案:
Sabberworm/CSSParser 类思路不适用,但 league/plates 允许传入 function($name, $data) { echo $this->render($name, $data); } 回调,可自行控制 flush 时机ReactPHP + amphp/http-server 构建异步 HTTP 响应,配合 yield 分块输出,绕过 PHP-FPM 的同步 OB 限制application/json + readline 或 SSE 推送真正要实现实时输出,关键不在“适配模板引擎”,而在放弃对完整 HTML 字符串的依赖 —— 模板即 PHP 脚本,输出即过程,缓冲控制权必须握在你自己手里。任何试图在 Twig render() 返回值上做 flush 的操作,都是在对抗它的设计前提。