必须确保APP_DEBUG=false、var/cache/prod/twig/可写且自定义Twig扩展不破坏缓存键稳定性,三者缺一不可;否则即使APP_ENV=prod,Twig仍退化为运行时编译。

关掉模板缓存后线上性能暴跌,不是简单重启就能恢复——必须确认 Twig 编译缓存路径、权限、环境变量三者全部对齐生产模式,否则即使 APP_ENV=prod 也会退化为运行时编译。
为什么 dev 环境关缓存不影响,prod 却不生效
Twig 模板缓存是否启用,完全取决于 debug 配置值,而非“是否手动删过缓存文件”。Symfony 3 中,debug: true(如 dev 环境)会强制禁用所有模板编译缓存,每次请求都重新解析 Twig 文件;而 debug: false 才允许生成并复用 var/cache/prod/twig/ 下的 PHP 编译文件。如果你在 .env 或 .env.local 里仍保留 APP_DEBUG=true,哪怕 APP_ENV=prod,Twig 也绝不会写入缓存。
- 检查命令:
php bin/console debug:container --env=prod | grep debug,输出中必须是debug: false - 若看到
debug: true,立刻修正.env:确保APP_ENV=prod和APP_DEBUG=false同时存在,且未被.env.local覆盖 - 改完后必须执行:
php bin/console cache:clear --env=prod && php bin/console cache:warmup --env=prod—— 缺少warmup会导致首次访问时现场编译,响应时间飙升数秒
var/cache/prod/twig/ 目录为空或不可写怎么办
Twig 缓存文件默认写入 var/cache/prod/twig/,该目录需满足两个硬性条件:存在、Web 服务器进程可写。常见问题不是“没生成”,而是“生成失败静默跳过”。
- 手动创建并赋权:
mkdir -p var/cache/prod/twig && chmod -R 775 var/cache/prod/twig(上线环境请用www-data用户属主,而非 777) - 验证 Web 服务器能否写入:临时加一行测试代码到控制器:
file_put_contents('var/cache/prod/twig/test.txt', 'ok');,访问触发后检查文件是否存在 - 若仍失败,检查 SELinux(CentOS/RHEL)或 AppArmor(Ubuntu)是否拦截了写入,临时用
setenforce 0测试是否为策略限制
模板修改后缓存没更新?别清整个 cache,只清 twig 子池
Twig 缓存独立于服务容器缓存,改了 .html.twig 文件后,不需要跑 cache:clear,那样会连路由、服务定义一起刷掉,引发不必要的冷启动。只需刷新 Twig 自己的缓存池即可。
- 推荐命令:
php bin/console twig:cache:clear --env=prod(Symfony 3.4+ 原生支持) - 低版本 Symfony 3.x 可用变通法:
rm -rf var/cache/prod/twig/*,然后确保下一次请求由 Web 服务器发起(而非 CLI),才能触发正确重建 - 注意:不要在 CLI 下执行模板渲染测试(如
php bin/console debug:twig)来验证,它走的是 CLI 环境,缓存路径和权限与 Web 请求不同
用了自定义 Twig 加载器或函数,缓存可能失效
如果你在 services.yaml 里注册了自定义 Twig_Loader_String、覆盖了 twig.loader,或通过 addFunction() 注入了闭包函数,Twig 将无法生成稳定哈希,导致缓存键频繁变动甚至完全跳过缓存。
- 检查是否有类似配置:
twig.loader: '@app.custom_twig_loader',若有,确认该 loader 实现了Twig\Loader\ExistsLoaderInterface并返回稳定getCacheKey() - 避免在 Twig 函数中传入 Closure 或对象实例,改用静态方法或 service id 引用
- 最简验证法:临时注释掉所有自定义 loader/function,看
var/cache/prod/twig/是否开始生成文件
真正卡住的往往不是“怎么开缓存”,而是 APP_DEBUG=false 这个开关是否在 prod 环境下真实生效、var/cache/prod/twig/ 是否被 Web 进程写入、以及自定义扩展是否破坏了 Twig 的缓存键稳定性——这三点漏掉任一,缓存就只是名义上开着。


















