必须重启Workerman主进程才能生效,因其常驻内存,代码一次性加载后不重启则始终执行内存副本;reload仅刷新子进程回调内动态加载的逻辑,不重载全局代码、配置或start.php变更。

修改 PHP 代码后 Workerman 没反应,不是缓存没清、不是浏览器问题、也不是 IDE 同步延迟——就是进程还在跑老内存副本。Workerman 是常驻进程,Worker::runAll() 启动后,所有业务代码被一次性加载进内存,后续请求全走这份快照。不杀进程,新代码永远不会执行。
为什么 php start.php reload 不生效?
Workerman 的 reload 命令只做一件事:向子进程发送 SIGUSR1 信号,让每个 Worker 进程重新执行其 onWorkerStart、onConnect、onMessage 等回调里的逻辑——但仅限于「动态加载」的部分。
- 顶层
require_once 'config.php'或全局函数定义,reload完全不碰 - 如果
onMessage里写的是硬编码逻辑(比如直接 echo "hello"),改完也不生效;必须改成require或自动加载类,如(new MessageHandler())->handle($data) -
opcache.enable=1时,即使 reload 成功,PHP 仍可能执行旧字节码;必须设opcache.validate_timestamps=0且调用opcache_invalidate(),或干脆关掉 opcache - 使用
Worker::$daemonize = true后,FileMonitor默认不工作,因为后台模式跳过了文件轮询逻辑
怎么写一个真正支持热更新的启动脚本?
核心原则:把所有可变逻辑塞进回调里,并通过自动加载或动态 require 加载,确保每次 reload 都会重新拉取。
- 在
start.php顶部加require __DIR__ . '/vendor/autoload.php';(ThinkPHP/Laravel 项目必须) - Worker 实例的
onMessage回调里不要写业务代码,而是 new 一个类或调用工厂方法:$handler = new \app\message\Handler(); $handler->process($connection, $data); - 避免在
onWorkerStart里初始化大对象(如 DB 连接池单例),否则 reload 后可能复用旧实例;应改在onMessage或onConnect中按需创建 - 若用自定义配置文件,可在
onWorkerStart中用filemtime()检查变更,再require重载(仅适用于纯数组配置,不含对象或闭包)
开发期自动重启比 reload 更可靠
别依赖 reload,开发阶段直接用文件监听 + 全进程重启,简单粗暴且 100% 生效。
立即学习“PHP免费学习笔记(深入)”;
- Linux 下用
inotifywait:while inotifywait -e modify,move_self,create ./app; do php start.php stop; pkill -f "start.php start"; php start.php start -d; done - macOS 用
fswatch替代inotifywait,命令结构一致 - 务必加
pkill -f "start.php start",因为php start.php stop经常残留子进程 - 启动时加
-d参数,但开发中建议先不加,前台运行方便看日志;确认无误后再切守护模式
最常被忽略的一点:Workerman 的 reload 机制从不重启主进程,只换 Worker 子进程。这意味着你改了 start.php 本身、Worker 构造参数、或任何在 Worker::runAll() 之前执行的代码,reload 根本无效——唯一解法是 stop → pkill → start。别省这一步,也别信“reload 就是热更”的说法。



















