PHP 8.2 预加载需手动配置且仅限 FPM/mod_php,Windows 不支持;必须启用 OPcache、设绝对路径 preload.php、指定 opcache.preload_user(root 启动时)、用 opcache_compile_file() 安全预编译,并通过 opcache_get_status()['preload_statistics'] 验证生效。

PHP 7.4 升级到 8.2 后,opcache 预加载(opcache.preload)不会自动生效——它需要手动配置、路径校验、用户权限适配,且 Windows 下完全不可用。
确认 PHP 8.2 环境已启用 OPcache 且支持预加载
预加载是 PHP 7.4 引入、PHP 8.x 持续演进的功能,但前提是 OPcache 必须在 FPM 进程中真正加载,而非仅 CLI 或 phpinfo() 页面里“看起来开了”:
-
php -m | grep opcache成功 ≠ 预加载可用;必须访问phpinfo()页面,找到Loaded Configuration File路径,然后确认该 ini 文件里有zend_extension=opcache.so(Linux/macOS)或带引号的绝对 DLL 路径(Windows),且重启的是php-fpm进程,不是 Apache/Nginx - 调用
opcache_get_status()必须返回数组,不能报Call to undefined function opcache_get_status() - 检查
php --ri opcache输出中是否含Preloading Support => enabled—— PHP 8.2 默认开启,但如果编译时加了--disable-opcache-file或用了某些精简版容器镜像,可能被关掉
写对 preload.php 并确保它被真实执行
预加载脚本不是“放那儿就行”,它会在 PHP-FPM master 进程启动时执行一次,任何 fatal error 都会导致 preload 失败且不报错(只静默跳过):
-
opcache.preload必须指向绝对路径:opcache.preload=/var/www/app/preload.php,相对路径、符号链接、~ 展开全部无效 -
preload.php文件权限需被 PHP-FPM worker 用户可读(如www-data或nginx),且不能有语法错误——建议先用php -l /var/www/app/preload.php校验 - 推荐用
opcache_compile_file()而非require_once:前者只编译不执行,避免预加载时意外触发 DB 连接、日志写入等副作用;后者会执行代码,若含if (ENV === 'prod')类逻辑,反而导致类未注册 - 不要递归加载整个
vendor/:Composer 自动加载器本身已优化,盲目 preload vendor 会显著拖慢 FPM 启动,并可能因类重复定义报Fatal error: Cannot declare class
处理 opcache.preload_user 权限问题
PHP 8.2 默认禁止 root 用户执行预加载,而多数 Linux 发行版的 php-fpm 默认以 root 启动 master 进程再 drop 权限——这会导致 preload 脚本运行失败:
立即学习“PHP免费学习笔记(深入)”;
- 如果 FPM master 以 root 启动,必须显式设置
opcache.preload_user=www-data(替换为你的 worker 用户名),否则 preload 直接被跳过 - 该用户必须对
preload.php及其require或opcache_compile_file()的所有目标文件有读取权限 - Windows 下该配置无效,且预加载功能本身不支持——升级到 PHP 8.2 后若还在 Windows 上跑,
opcache.preload字段会被忽略,无报错也无效果
验证预加载是否真生效
光看 phpinfo() 里的 “Preloaded Scripts” 区块不够,得看运行时行为:
- 访问
opcache_get_status()['preload_statistics'],检查scripts数量是否 > 0,memory_consumption是否明显上升 - 故意在某个预加载类里加个
die('preloaded');,重启 php-fpm 后首次请求应立即终止并输出——若没触发,说明 preload.php 根本没跑 - 用
opcache_is_script_cached('/path/to/preloaded/file.php')返回true才算成功缓存;注意该函数对未预加载但普通 OPcache 缓存的文件也返回 true,所以必须结合preload_statistics判断 - 上线后改了预加载的类,页面不更新?不是缓存没刷新,而是你忘了:预加载内容只能通过重启 php-fpm 清除,
opcache_reset()对它完全无效
最常被忽略的一点:预加载只在持久化进程模型下起作用(如 PHP-FPM、Apache mod_php),CLI 脚本每次都是新进程,preload 无意义;另外,Docker 容器若用 php -S 或 supervisord 直接跑 php-fpm 但没设好用户切换,opcache.preload_user 就成了摆设。



















