ThinkPHP + Swoole 热更新本质是文件监听触发 SIGUSR1 信号,使 Swoole master 进程平滑重启 worker,从而重新加载代码;需禁用 opcache 或配置校验、业务逻辑必须在 onWorkerStart 中动态加载,且仅限开发环境(APP_DEBUG=true)启用。

ThinkPHP + Swoole 的热更新不是靠 ThinkPHP 自己“重载 PHP 文件”,而是靠 Swoole 的 reload() 机制触发 worker 进程重启,从而重新加载新代码。不改配置、不发信号、不关 opcache,reload() 就是空转。
think-swoole 的 hot_update 是什么
它只是个文件监听 + kill -USR1 的封装,不是魔法。启用后会在开发期自动监听 app/、config/ 等目录下 *.php 文件变化,一旦检测到修改,就向 Swoole master 进程发 SIGUSR1 信号——本质仍是 Swoole 的 worker 平滑退出+拉起流程。
- 只在
APP_DEBUG = true时默认开启;生产环境必须关掉,否则 inotify 监听开销明显,且任意文件保存都可能触发 reload - 监听路径写死在 think-swoole 源码里(如
app/、config/、route/),不支持自定义扩展,改 vendor 或 runtime 下的文件不会触发 - 它不处理 opcache,也不重连数据库或重初始化单例——这些得你手动在
onWorkerStart里做
reload() 不生效的三个硬性前提
reload() 返回 true ≠ 新代码跑起来了。以下任一条件不满足,都会导致“看起来 reload 了,但请求还是旧逻辑”:
-
opcache.enable=1且opcache.validate_timestamps=1未设为 0 或opcache.revalidate_freq太大 → 即使 worker 重启,opcode 还是旧的 - 业务代码是启动时
require_once进来的(比如在Server->on('Start')里一次性加载全部控制器)→ reload 后不会再次执行,新文件根本没被 include - 信号没发给 master 进程 PID,而是发给了 worker 或错用了
kill -HUP→ Swoole 只响应SIGUSR1,且只由 master 进程接收
如何让 onWorkerStart 真正“每次 reload 都重载”
这是最容易被忽略的一环:Swoole worker 重启后,onWorkerStart 会再执行一次,但如果你把 require 写在了全局作用域或 onStart 里,它只跑一次。必须把业务入口动态加载逻辑放到 onWorkerStart 中:
立即学习“PHP免费学习笔记(深入)”;
$server->on('WorkerStart', function (Server $server, int $workerId) {
// ✅ 正确:每次 worker 启动都重新 require,确保加载最新代码
require_once __DIR__ . '/app/Http/Controllers/UserController.php';
// ❌ 错误:只在进程启动时执行一次,reload 后不重复加载
// require_once __DIR__ . '/bootstrap/app.php';
});
- 不要在
onStart或文件顶层require业务类,否则 reload 完全无效 - 如果用 DI 容器或单例,必须在
onWorkerStart里重建实例,不能复用上一个 worker 的静态属性 - DB 连接、Redis 实例等长连接资源,也要在
onWorkerStart里 new 或 reconnect,避免复用失效连接
生产环境别信 auto-reload,用版本软链 + reload 组合
inotify 监听不适合生产:文件系统压力、误触发、权限问题太多。更稳的做法是发布时切软链 + 主动 reload:
- 部署脚本把新代码放
/var/www/myapp/releases/202605081130/,然后ln -sfn /var/www/myapp/releases/202605081130 /var/www/myapp/current - 所有
require路径基于CURRENT_PATH(即软链目标),确保 reload 后加载的是新目录下的文件 - 最后
kill -USR1 $(cat /var/run/swoole.pid)触发 worker 更新,整个过程无 downtime
这个流程里,真正起作用的从来不是“热”,而是“可预测的进程替换”——别指望 PHP 运行时能 patch 一个正在执行的函数,worker 重启才是唯一可靠路径。


















