swoole热更新本质是worker进程重启而非代码重载,include/require仅在新进程启动时执行一次,不会自动刷新已加载类、函数或常量;reload后旧进程退出、新进程从入口文件重新解析,但跨进程重复define或声明会报错,需用配置中心、环境变量或opcache失效控制等替代方案。

PHP 的 include 和 require 在 Swoole 热重启(reload)场景下,行为和普通 CLI/FPM 完全不同——它们不会自动重载,且多数情况下根本不起作用。
reload 时 include/require 不会重新执行
Swoole 的 reload(如 kill -USR1 或 server->reload())本质是「平滑重启 Worker 进程」:旧进程处理完当前请求后退出,新进程 fork 后从入口文件(如 server.php)**重新开始执行**。但注意:
- 它不是「重新 require 全部已加载文件」,而是启动一个全新 PHP 进程,从头解析入口脚本
- 所有在
require或include中加载的代码,只在新进程启动时执行一次;已加载的类、函数、常量不会被“刷新” - 如果你在
onWorkerStart里用include 'config.php',每次 reload 都会再读一次——但这属于你主动写的行为,不是语言机制保证的
为什么不能靠 include_once 或 require_once 实现热更
因为 Swoole 进程常驻,_once 的判定基于「当前进程生命周期内是否已加载过该路径」。reload 后是新进程,判定重置,所以 include_once 会再次生效——但这不等于“热更新”,只是重新加载。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
真正的问题在于:
- 如果
config.php里定义了常量(define('DB_HOST', '127.0.0.1')),reload 后新进程会重新 define,没问题 - 但如果它定义了函数或类,而你改了函数体却没改文件名,PHP 会报
Fatal error: Cannot redeclare xxx()—— 因为新进程仍会尝试重复定义(include_once只防同一进程内重复,不防跨进程语义冲突) -
require_once对路径敏感:用require_once 'config.php'和require_once __DIR__ . '/config.php'在同一进程里会被视为两个文件,reload 后都可能触发重载
reload 场景下该用什么替代 include/require
直接硬 reload 文件不是可靠方案。真实项目中应规避运行时动态包含配置或逻辑文件,转而使用:
- 配置中心(如 etcd、Consul)+ 定期轮询拉取,避免重启依赖文件变更
- 环境变量注入(
putenv()+getenv()),配合 Docker/K8s 配置热更新 - OPcache 失效控制:修改文件后调用
opcache_invalidate($file, true),但仅对include有效,且需确保opcache.enable_cli=1(Swoole Worker 是 CLI 模式) - 把可变逻辑抽成独立 HTTP/gRPC 服务,主进程只负责转发,彻底解耦 reload 依赖
最常被忽略的一点:Swoole reload 本身不触发任何文件重载逻辑,它只管进程启停。所谓“热更新”必须由你手动设计数据加载时机和缓存策略,而不是指望 include 自动感知变化。









