opcache.preload 失效主因是路径错误、autoload.php 有副作用、全量加载低效及 reload 未重启 master 进程;须用 DIR 绝对路径 require、改用 classmap、精准筛选核心类、修改后 systemctl restart php-fpm。

opcache.preload 配置后类仍没预加载?检查 preload.php 的 require 路径是否绝对
preload.php 里用 require 或 require_once 加载类文件时,相对路径会以 PHP 进程启动目录(通常是 web server root 或 CLI 当前目录)为基准,不是 composer autoload 目录。结果就是文件找不到,opcache.preload 静默失败,类根本没进 OPCache。
实操建议:
- 所有
require必须用__DIR__ . '/path/to/Class.php'这种绝对路径写法 - 不要依赖
getcwd()或dirname(__FILE__)拼接,容易错;直接用__DIR__ - 用
file_exists()+is_readable()在 require 前校验,避免 preload 失败不报错 - composer 自动生成的
vendor/autoload_classmap.php是绝对路径数组,可直接遍历 require
为什么 vendor/autoload.php 不能直接 preload?它本身会触发 autoloader 注册
vendor/autoload.php 不是纯类定义文件,它会执行 ComposerAutoloaderInit 初始化、注册 spl_autoload_register 回调——而 opcache preload 要求脚本只做“定义”,不能有运行时副作用(如注册全局 autoloader、修改 ini 设置、连接数据库等),否则 PHP 启动直接报 Cannot preload class … because the autoloader has not been registered yet。
实操建议:
- 不要
require 'vendor/autoload.php',改用classmap或filesautoload 类型生成的静态列表 - 运行
composer dump-autoload --classmap-authoritative --no-dev,确保vendor/composer/autoload_classmap.php包含全部生产类 - preload.php 中只做
foreach ($classmap as $class => $file) { require $file; },跳过 autoload.php
preload.php 里 require 太多文件导致 PHP 启动卡顿?控制加载范围比盲目全量更关键
composer 项目常有数百个类,全量 require 到 preload.php 会导致 PHP 主进程初始化变慢,反而抵消 opcache 带来的请求延迟收益。更糟的是,部分类(如命令行工具、测试辅助类、未使用的扩展类)根本不会在 Web 请求中用到,白占内存。
实操建议:
- 用
composer show --tree和业务路由分析,只 preload 入口控制器、核心 service、entity、repository 等高频路径类 - 排除
Tests/、Command/(除非是 worker 进程)、Fixtures/、Examples/ - 用
opcache_get_status()['preloaded_scripts']验证实际加载了哪些文件,别信配置写了就生效 - 生产环境建议配合
opcache.memory_consumption调整,避免 preload 后 OPcache 内存溢出被自动清空
PHP-FPM reload 后 preload 失效?确认 opcache.restrict_api 和权限链路
PHP-FPM reload(kill -USR2 或 systemctl reload php-fpm)会重启 worker 进程,但 preload 只在主进程(master)启动时执行一次。如果 master 进程没重启,preload 就不会重跑——而你改了 preload.php 却没重启 master,新类永远进不来。
实操建议:
- 修改 preload.php 后必须
systemctl restart php-fpm(不是 reload),否则无效 - 检查
opcache.restrict_api是否设为非空值(如/var/www),它会禁止不在该路径下的脚本调用opcache_*()函数,影响状态排查 - 确认 PHP 用户(如
www-data)对 preload.php 及所有 require 文件有读取权限,无权限时 preload 静默跳过 - 错误日志里搜
Failed to preload或Unable to open,比看 HTTP 响应更早发现问题
preload 的边界很硬:它发生在 PHP 解析器最开始阶段,不走 autoloader,不认命名空间自动映射,也不容错。一个路径错、一个权限缺、一次 reload 没重启 master,整个预热就归零。别把它当缓存用,要当启动配置来守。










