全局变量和静态属性在worker模式下跨请求残留,因进程常驻内存而持续存在,易致数据污染;应改用协程本地存储或显式清理,禁用非必要全局状态。

全局变量和静态属性在Worker模式下会跨请求残留
Worker模式让PHP脚本常驻内存,static 属性、global 变量、$_SESSION(未启用session handler时)、甚至 define() 的常量一旦定义就持续存在。这不是bug,是设计使然——但很多老项目习惯把临时状态塞进全局变量里,比如用 $GLOBALS['current_user_id'] 存用户ID,下次请求进来它还是上一个用户的值。
- 检查所有
static $xxx声明,确认是否真需要跨请求保持;否则改用函数参数或依赖注入传递 - 禁用
register_globals(FrankenPHP默认不支持,但遗留代码可能手动模拟) - 避免在入口文件或框架启动阶段写入全局数组,例如
$GLOBALS['config'] = loadConfig(); - 用
var_dump(get_defined_vars())在请求末尾快速扫一眼意外挂载的变量
数据库连接没显式关闭或复用不当
传统FPM每次请求结束自动释放PDO/MySQLi连接,Worker模式下连接对象可能被反复复用。如果代码里写了 $pdo = new PDO(...) 但没调用 $pdo = null 或 $pdo->close(),连接会一直占着,直到超时或连接池满。
- 确认PDO构造时启用了
PDO::ATTR_PERSISTENT => true—— 这是Worker模式下的推荐做法,但必须配合连接池管理逻辑 - 不要在循环中反复 new PDO;应提取为单例或容器服务,且确保连接异常后能重建
- 检查ORM配置(如Laravel的
DB_CONNECTION=sqlite),SQLite在Worker下容易因文件锁报错,建议换MySQL或PostgreSQL - 用
netstat -an | grep :3306观察连接数是否缓慢上涨,这是典型泄漏信号
没重写入口逻辑,直接套用传统index.php
FrankenPHP Worker模式要求你主动接管请求生命周期,不能靠 php_server 指令自动转发。常见错误是把Laravel的 public/index.php 直接当Worker脚本,结果 $_SERVER 不全、$_GET/$_POST 为空、路由解析失败。
- Worker脚本必须调用
frankenphp_handle_request(),且只调用一次(不能放在循环里重复调) - 入口需手动解析
$_SERVER['REQUEST_URI']和$_SERVER['REQUEST_METHOD'],不能依赖框架自动识别 - TP6/Laravel等框架需改写启动方式:例如TP6要把
thinkphp/start.php包进frankenphp_handle_request()回调中 - 禁止在Worker脚本里执行
exit或die—— 这会让整个Worker线程退出,后续请求全部失败
日志写入、文件操作没做并发隔离
多个请求共享同一个Worker进程,如果都往同一个日志文件追加写(如 file_put_contents('app.log', $msg, FILE_APPEND)),会出现内容错乱、覆盖、甚至IO阻塞。
- 改用日志库(如Monolog)并配置
RotatingFileHandler,它内部做了flock保护 - 避免直接
fopen(..., 'a'),尤其在高并发场景下;如必须用,加上flock($fp, LOCK_EX) - 临时文件路径别硬编码
/tmp/log.txt,应带唯一标识,例如sprintf('/tmp/app-%d.log', getmypid()) - 检查
file_get_contents()读取配置文件的逻辑——如果配置会动态更新,记得加clearstatcache()和opcache_invalidate()
$GLOBALS 塞个调试标记,或者用 time() . rand() 生成临时文件名。这些在FPM里每请求一清,在Worker里就是静默污染源。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











