FrankenPHP 不支持 Symfony 热重载因其无内置文件监听机制,需配合 watchexec 与 kill -USR2 实现软重启;关键前提是启用 opcache.enable_cli=1,否则 USR2 信号无效。

FrankenPHP 本身不支持 Symfony 开发环境的热重载(如 symfony server:start 那种文件变更自动 reload)——它没有内置文件监听机制,也不能像 PHP-FPM 那样靠外部工具触发重启。 你得自己搭一层监听 + 信号控制,否则改完 src/ 或 config/ 文件,worker 进程根本不会感知变化,缓存和容器状态全卡在旧版本里。
为什么 frankenphp php-server 不会响应文件变更
FrankenPHP 的 php-server 命令本质是启动一个常驻的 Go + PHP 进程,所有 PHP 代码(包括 Symfony 容器)在首次请求时初始化后就长期驻留内存。它不像 symfony server 那样基于 inotifywait 或 fsnotify 主动监听文件系统事件,也不会在检测到变更时向 worker 发送 SIGHUP 或触发重新引导。
常见错误现象:
- 修改了
src/Controller/HomeController.php,刷新页面还是旧逻辑 - 改了
config/packages/cache.yaml,cache:pool:clear没用,因为容器没重建 - 执行
composer dump-autoload后,新类仍报Class not found
用 watchexec + kill -USR2 实现最小可行热重载
Symfony 官方文档明确指出:FrankenPHP 的 worker 模式支持通过 USR2 信号触发优雅重启(soft reload),前提是进程以 --worker 模式启动且未禁用 opcache.enable_cli=1。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 确保项目已启用
APP_ENV=dev和OPcache(opcache.enable_cli=1必须开启,否则USR2不生效) - 用
watchexec监听关键目录:src/、config/、templates/、translations/ - 启动命令拆成两步:先后台运行 FrankenPHP,再用
watchexec触发信号
示例(Linux/macOS):
frankenphp --worker --env APP_ENV=dev php-server & WATCH_PID=$! watchexec -e php,yaml,xml,twig --on-change "kill -USR2 $WATCH_PID" --recursive src/ config/ templates/ translations/
注意:kill -USR2 不会中断正在处理的请求,但会等当前请求结束才重建 worker 环境,所以有轻微延迟;watchexec 需要单独安装(brew install watchexec 或 curl -L https://github.com/watchexec/watchexec/releases/download/v1.24.0/watchexec_1.24.0_amd64.deb)。
开发时绕过 worker 模式的替代方案
如果你只是临时调试、不想折腾信号和监听,直接退回到 classic 模式更省事——它每次请求都完整启动 PHP 生命周期,天然“热重载”,代价是性能掉回 PHP-FPM 水平。
启动命令改为:
frankenphp --env APP_ENV=dev php-server
这个模式下:
- 无需
--worker,也无需USR2信号 - 修改任何 PHP 文件,下次请求自动加载新代码(
opcache.revalidate_freq=0在 dev 下默认生效) - 适合单点调试、CI 测试或低频开发场景,但别在压测或本地长连接测试中用
真正容易被忽略的是 opcache.enable_cli 这个开关——它默认为 0,而 USR2 软重启依赖 OPcache 的 CLI 模式重载能力。不显式设为 1,哪怕其他都配对了,热重载也永远不会触发。



















