FrankenPHP Worker模式本质是伪常驻,复用PHP-FPM进程池模型,每次请求仍重建运行时环境;Swoole才是真常驻,onWorkerStart初始化后所有请求共享同一PHP实例与内存空间。

FrankenPHP Worker模式本质仍是“伪常驻”
FrankenPHP 的 Worker 模式不是真正意义上的常驻进程,它复用的是 PHP-FPM 的 pm=static 或 pm=dynamic 进程池模型,每个 Worker 进程仍遵循“请求来 → 初始化 → 执行 → 销毁”的生命周期。虽然它通过共享内存(如 opcache.preload、apcu)缓存类定义和配置,但全局变量、静态属性、PDO 实例、连接句柄等仍会在每次请求后被销毁——这和 Swoole 的 onWorkerStart 仅执行一次、所有 onRequest 共享同一 PHP 环境有根本区别。
常见错误现象:Undefined variable 在 FrankenPHP 中不报错,但第二次请求就丢失值;而 Swoole 下若在 onRequest 中未 unset 大数组,内存会持续增长。
- FrankenPHP Worker 启动时加载预编译脚本,但不保留运行时对象状态
- Swoole Worker 进程启动后,
new Redis()、static::$cache、global $db全部跨请求存活 - FrankenPHP 的“复用”集中在 opcode 和类结构,而非运行时堆内存
Swoole 的常驻机制直接绕过 PHP-FPM 请求边界
Swoole 的 Worker 进程从 onWorkerStart 开始就持有完整 PHP 解释器实例,后续所有 HTTP 请求都作为协程在同一个进程中调度,不重建符号表、不重载类、不重连数据库。这意味着你可以在 onWorkerStart 中初始化连接池,在 onRequest 中直接复用 $this->redisPool->get(),而 FrankenPHP 即使开启 opcache.enable_cli=1,也无法避免每次请求重新 new 对象或重建 PDO。
性能影响明显:Swoole 下单个 Worker 处理 1000 次请求,数据库连接只建立 1 次;FrankenPHP 下则是 1000 次连接/断开,哪怕用了 PDO::ATTR_PERSISTENT,也受限于 FPM 进程回收策略,实际复用率极低。
立即学习“PHP免费学习笔记(深入)”;
- Swoole 的
Coroutine\run()内协程共享父作用域变量,FrankenPHP 无此能力 - Swoole 支持
Coroutine\Http\Client异步并发调用,FrankenPHP 只能靠curl_multi或外部进程模拟 - FrankenPHP 的
php-fpm.conf配置项(如pm.max_requests)依然生效,会强制重启 Worker,打断长连接
共享内存的使用方式完全不同
FrankenPHP 借助 APCu 或 shmop 实现跨请求数据共享,但必须显式 apcu_store()/apcu_fetch(),且无法存储资源类型(如 mysqli 句柄);Swoole 则天然支持全局变量、静态类属性、单例对象跨请求访问,甚至可通过 Co::sleep() 让协程挂起而不阻塞整个 Worker。
容易踩的坑:apcu_clear_cache() 在 FrankenPHP 中会清空所有 Worker 共享数据,而 Swoole 下若在 onWorkerStart 初始化了 static::$config,除非手动 unset 或重启进程,否则不会失效。
- FrankenPHP 的共享内存是“键值对 + 序列化”,Swoole 是“原生内存地址直读”
- FrankenPHP 不支持协程间内存隔离,Swoole 有
Coroutine\Memory提供独立栈空间 - FrankenPHP 的
$_SERVER每次请求都是全新副本,Swoole 的$_SERVER在 Worker 生命周期内可被修改并持久化
进程模型决定扩展能力上限
FrankenPHP Worker 是 PHP-FPM 的增强版,底层仍依赖 fork() 创建子进程,无法突破 Unix 进程调度瓶颈;Swoole 的 Reactor 线程 + Worker 进程混合模型,让单机万级 WebSocket 连接成为常态,而 FrankenPHP 在 5000+ 并发下就容易触发 FPM process busy 或超时。
典型场景差异:实时聊天室需要维持长连接和广播状态,Swoole 可在内存中维护 ConnectionMap;FrankenPHP 只能退回到 Redis Pub/Sub + 轮询,延迟和资源开销陡增。
- FrankenPHP 无法监听
SIGUSR2热重启,Swoole 支持reload信号平滑更新代码 - FrankenPHP 的日志写入依赖
fopen("php://stderr"),Swoole 可直接调用Swoole\Logger异步刷盘 - FrankenPHP 不支持
task worker异步任务队列,复杂业务需额外引入 Beanstalkd 或 Redis Queue
onRequest 结束前清理临时大对象,否则 Worker 进程越跑越慢。



















