worker 模式下 date_default_timezone_set() 会污染后续请求,因其修改的是常驻 php 进程的全局状态;正确做法是在入口文件顶部一次性设置,运行时改用 datetimezone 显式传参。

date_default_timezone_set() 在 FrankenPHP Worker 模式下会污染后续请求
因为 Worker 模式让 PHP 进程常驻内存,date_default_timezone_set() 的调用效果不会随请求结束而重置——它修改的是当前 PHP 进程的全局运行时状态。一旦某个请求执行了该函数,后续所有请求(哪怕来自不同用户、不同路由)都会继承这个时区,直到进程重启或被覆盖。
为什么普通 FPM 或 CLI 下不明显,Worker 下就出问题
传统 PHP-FPM 每次请求都启动全新进程,date_default_timezone_set() 的影响只存活于单次生命周期;CLI 脚本也是一次性执行。而 FrankenPHP Worker 模式下,一个 PHP worker 可能连续处理成百上千个请求,date_default_timezone_set('Asia/Shanghai') 如果在某个请求里被动态调用(比如根据用户偏好切换),就会把整个 worker 的默认时区永久改掉。
- 不是“设置一次就生效”,而是“设置一次就卡死”
- 多个并发请求可能交错执行,A 请求设了
UTC,B 请求紧接着设了Asia/Shanghai,结果 C 请求拿到的就是Asia/Shanghai——完全不可预测 -
date_default_timezone_get()返回值在 worker 生命周期内可变,不能当作稳定配置依据
正确做法:别在请求中调用 date_default_timezone_set()
Worker 模式下,时区必须在进程启动前就固定好,而不是运行时动态改。所有依赖时区的操作,应显式传入 DateTimeZone 对象,而非依赖全局默认。
- 入口文件(如
public/index.php)最顶部就调用一次date_default_timezone_set('Asia/Shanghai'),且仅此一次 - 禁止在控制器、中间件、模型里再调用该函数——哪怕加了
if判断也不行 - 需要按用户时区展示?用
new DateTime($time, new DateTimeZone($userTz))显式构造,而不是改全局 - 数据库读写时间一律用 UTC 时间戳或
DateTimeImmutable+ 明确时区对象,避免隐式转换
验证是否踩坑:检查日志和 time() / date() 行为是否错位
如果发现某些请求返回的时间比实际早/晚整小时,或 date('c') 和 date('U') 之间换算异常,大概率是时区被中途篡改过。尤其注意错误日志里是否混着不同格式的时间(比如一条日志是 2026-10-04T14:13:00+08:00,下一条却是 2026-10-04T06:13:00Z)。
- 在 worker 启动后立即记录
date_default_timezone_get()结果,后续请求不再查 - 避免在
frankenphp_handle_request()循环体内做任何全局状态修改 - 时区不是“业务配置”,它是运行环境契约——改它就像改
memory_limit,得在进程初始化阶段完成
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











