PHP 8.4 的 opcache.preload 文件仅在 FPM master 进程启动时加载一次,不支持热更新;必须重启 master 进程(如 systemctl restart php84-fpm)才能生效,reload 或 USR2 信号无效。

opcache.preload 文件被加载后无法热更新
PHP 8.4 的 opcache.preload 是一次性预编译并常驻内存的,它在 PHP-FPM master 进程启动时就执行完毕,之后所有 worker 进程共享这份字节码。这意味着:preload 文件本身、以及它 require 或 include 进来的所有脚本,**都不会响应文件修改、不走 opcache.validate_timestamps 校验、也不受 opcache_invalidate() 影响**。
常见错误现象包括:改了 preload.php 里的类定义,或改了它引入的 vendor/autoload.php 或核心服务类,但请求仍跑旧逻辑;opcache_get_status()['preloaded_scripts'] 显示脚本已加载,但内容明显过期。
- preload 是“只加载一次”的机制,不是缓存,没有刷新入口
- 即使你把
opcache.validate_timestamps=1和opcache.revalidate_freq=0都设对了,对 preload 路径下的文件完全无效 - 宝塔用户尤其要注意:面板里点“重载 PHP”通常只发
reload信号,worker 进程不重启 → preload 不重载
必须重启 PHP-FPM master 进程才能更新 preload
opcache.preload 只在 master 进程初始化阶段执行,所以只有让 master 进程彻底退出再拉起,才能重新解析 preload 文件。用 systemctl restart php84-fpm(注意版本号)是最稳妥的方式;reload 或 kill -USR2 都不行。
验证是否生效的方法:发布后立刻访问一个能触发 preload 内容的接口,同时查 PHP 错误日志(比如在 preload.php 开头加 error_log("preload v2.1 loaded at " . date('H:i:s'));),看时间戳是否更新。别只依赖浏览器刷新 —— 如果 worker 还在复用旧 preload,新请求可能继续命中旧内存。
立即学习“PHP免费学习笔记(深入)”;
- 多机部署时,每台都要单独执行
systemctl restart php84-fpm - 使用宝塔的,进【软件管理】→ 找到 PHP 8.4 → 点【重启】,不是【重载】
- CI/CD 发布脚本里,不能漏掉这步;否则自动部署等于白部署
preload 文件里不要 include 动态变更的业务代码
很多人把 preload.php 当成“全局自动加载入口”,在里面 require_once 'app/Helper.php' 或 require_once __DIR__ . '/../config/database.php'。一旦这些文件频繁迭代,每次发布都得重启 FPM,失去 preload 提升稳定性的意义。
真正适合 preload 的只有三类东西:vendor 中稳定不变的类(如 Symfony 组件、Laravel 核心抽象类)、项目中极少改动的基类/接口、以及你自己写的纯函数工具库(无副作用、无配置依赖)。
- 业务控制器、路由定义、配置数组、数据库连接初始化 —— 全部移出 preload
- 如果必须预加载某段逻辑,把它拆成独立的、语义稳定的类,再通过 DI 容器在运行时注入,而不是硬 require 进 preload
- 检查
opcache_get_status()['preloaded_scripts']列表,确认里面没混入app/或config/下的路径
开发环境建议直接禁用 preload
本地或预发环境开 opcache.preload 只会拖慢调试节奏。改一行代码就要等 FPM 重启,还容易因 preload 报错导致整个 PHP 服务起不来(比如类重复定义、命名空间冲突)。
推荐做法:在 php.ini 中用条件配置隔离。例如:
opcache.enable=1 opcache.preload=/www/wwwroot/myapp/preload.php ; 开发环境注释掉下面这行,或设为空 ; opcache.preload=
或者更严谨地,在不同环境用不同 ini 文件(如 php.ini.dev 不含 preload 配置),避免误操作。
线上确实需要 preload 时,务必确保 preload.php 本身是 Git 可追踪、CI 可构建、发布流程可审计的静态资产 —— 它本质上已是部署产物的一部分,不是普通 PHP 文件。



















