旧项目直接套用FrankenPHP Worker模式易出数据污染、连接泄漏或静默失败,因进程常驻导致static变量、全局状态、未管理连接跨请求残留,须主动清理并重写入口逻辑。

旧项目直接套用 FrankenPHP 的 worker 模式,十有八九会出数据污染、连接泄漏或静默失败——不是 FrankenPHP 有问题,而是它把原来被 PHP-FPM 隐式掩盖的问题全暴露出来了。
检查所有 static 变量和全局状态是否跨请求残留
Worker 模式下进程常驻,static $cache、global $db、define('RUN_ENV', 'prod') 这类语句一旦执行就永远在内存里。下次请求进来,值还是上一次留下的。
- 用
grep -r "static \$\|global \$\|define(" app/快速扫一遍,重点看服务提供者、入口文件、工具类 - 特别警惕
$_SESSION未配 session handler 的情况:FrankenPHP 不自动启动 session,$_SESSION会变成空数组但不报错,导致登录态丢失 - 禁用任何手动模拟
register_globals的逻辑(比如遍历$_GET赋值到全局变量),FrankenPHP 完全不支持该行为
验证数据库和缓存连接是否显式管理
传统 FPM 每次请求结束自动释放 PDO/Redis 连接;Worker 模式下不关就一直挂着,连不上新库、事务不提交、连接池爆满都是常见现象。
- 检查所有
new PDO()或new Redis()是否伴随unset($conn)或置为null,尤其在异常分支里 - 确认 PDO 构造时用了
PDO::ATTR_PERSISTENT => true,否则连接不会复用,反而更慢 - 运行
netstat -an | grep :6379(Redis)或ss -tnp | grep :3306(MySQL),观察连接数是否随请求持续上涨
重写入口逻辑,不能直接复用 public/index.php
FrankenPHP Worker 模式不走 FastCGI 协议,$_SERVER 字段缺失、$_GET/$_POST 为空、路由解析失败,基本都源于入口没适配。
立即学习“PHP免费学习笔记(深入)”;
- 必须用
frankenphp_handle_request()接管整个生命周期,且只调用一次——别包进 while 循环里 - Laravel/TP6 等框架需改启动方式:例如 TP6 要把
thinkphp/start.php包进回调函数,而不是靠php_server指令转发 - 禁止在 worker 脚本里写
exit或die,这会让整个 worker 线程退出,后续所有请求直接 502
确认 $_SERVER 关键字段是否与原环境一致
FrankenPHP 的 HTTP 层由 Caddy 驱动,不是 Nginx+FastCGI,$_SERVER['HTTPS']、$_SERVER['REQUEST_URI']、$_SERVER['SCRIPT_NAME'] 默认值和 FPM 不同,框架 URL 生成、跳转、路由全依赖这些。
- 加一行调试代码:
var_dump(array_intersect_key($_SERVER, array_flip(['REQUEST_URI', 'HTTPS', 'HTTP_X_FORWARDED_PROTO', 'SCRIPT_NAME']))); - 若
HTTPS是空或off,需在 Caddyfile 的php块里加env HTTPS on - 若
SCRIPT_NAME是/index.php(FPM 常为空),Laravel 的url()可能多出重复路径,需在config/app.php中设'url' => env('APP_URL', 'https://example.com')显式兜底
真正麻烦的从来不是“怎么开 worker”,而是你得承认:那个靠每次请求重启来掩盖状态混乱的老项目,现在必须直面它的设计债务。变量清理、连接释放、入口抽象——这些动作在 FPM 下可选,在 FrankenPHP 下是必选项。



















