
为什么不能在 Worker 进程里 require_once vendor/autoload.php
因为 vendor/autoload.php 本身只执行一次注册逻辑(spl_autoload_register),但它内部加载的映射表(如 autoload_psr4.php)是静态生成的——Swoole 的 Worker 进程重启(比如 max_request 触发或 SIGUSR1 平滑重启)并不会重新执行 autoload.php,也不会重建 ClassLoader 实例。你每次在 onWorkerStart 里 require_once,实际只是重复调用已注册的 autoload 回调,不刷新映射、不重载类定义。
常见错误现象:
-
Class not found:改了命名空间但没跑composer dump-autoload -
Cannot redeclare class:多个 Worker 同时加载了含class声明的files脚本 - 热更新后行为未变:类文件已改,但旧字节码仍在 OPcache 或内存中
预热必须在 Master 进程启动前完成
真正有效的预热,是让所有需要的类在 Swoole 主进程 fork Worker 之前就完成加载和解析。这意味着:
- 入口文件第一行必须是
require_once __DIR__ . '/vendor/autoload.php' - 紧接着手动触发关键类的加载(不是
new,而是class_exists('App\Server')或interface_exists('App\Contract\Handler')) - 如果用了
autoload.files,它的脚本也会在此时被 include —— 注意检查是否含副作用(如register_shutdown_function、全局函数定义) - OPcache 预加载(
opcache.preload)只能在 PHP 启动时生效,不能在 Swoole 运行时动态触发;它适合加载稳定不变的核心类,但不能覆盖files中的副作用脚本
示例(server.php 开头):
require_once __DIR__ . '/vendor/autoload.php';
// 预热核心命名空间
class_exists('App\Http\Router') ?: null;
class_exists('App\Service\Cache') ?: null;
// 若有 files 加载,确保只在主进程跑一次(避免 Worker 多次执行)
if (function_exists('swoole_getpid') && swoole_getpid() === getmypid()) {
// 这里可安全执行依赖 side-effect 的初始化逻辑
}
PSR-4 映射表更新后必须重启整个 Swoole 进程
修改 composer.json 的 autoload.psr-4 或增删类文件后,仅 composer dump-autoload 不够——新生成的 autoload_psr4.php 只在下次 require vendor/autoload.php 时生效。而 Swoole 的常驻特性决定了:
-
onWorkerStart不会重新 require autoload 文件 -
reload_async或max_request重启 Worker,不会重建 ClassLoader - 唯一可靠方式是发送
SIGTERM或SIGUSR2全局重启主进程(不是SIGUSR1)
开发期建议配合 inotify 监控 composer.json 和 app/ 目录,变化时自动执行:
composer dump-autoload --optimize && kill -SIGTERM $(cat swoole.pid)
files 类型加载要按进程隔离处理
autoload.files 列表里的脚本会在每次 require vendor/autoload.php 时无条件执行。在 Swoole 多 Worker 场景下,这会导致:
- 每个 Worker 都执行一遍
helpers.php,可能重复定义函数 - 若脚本里有
register_shutdown_function,多个 Worker 注册同一 handler,崩溃时行为不可控 - 全局变量污染(如
$GLOBALS['config']在不同 Worker 里互不影响,但初始化逻辑被多次执行)
解决方案只有两个:
- 把
files移到onWorkerStart回调里,显式控制执行时机:require __DIR__ . '/src/helpers.php'; - 彻底删除
files,改用 PSR-4 + 工具类静态方法封装函数逻辑(例如Helpers::format())
最容易被忽略的一点:即使你把 files 放进 onWorkerStart,也得确认该文件不依赖尚未加载的类——否则 require 会触发 autoload,而此时 autoloader 已注册,但路径映射可能还没覆盖到你的新类。


















