Composer 不提供 opcache.preload 功能,仅生成 autoload 映射;必须先运行 composer dump-autoload -o 生成 classmap,再在 preload.php 中按需 require 已知类文件,并通过 php.ini 配置 opcache.preload 绝对路径后重启 PHP 进程。

Composer 本身不提供类文件预热(pre-warm)或直接触发 opcache.preload 的能力;它只负责生成自动加载映射(vendor/autoload.php),而 opcache.preload 是 PHP OPcache 的独立机制,需手动配置并由 Web 服务器启动时加载。两者必须协同,但不能混为一谈。
composer dump-autoload 不能替代 preload,但它是前提
运行 composer dump-autoload(尤其是加 -o 或 --optimize)会生成优化后的 vendor/composer/autoload_classmap.php 和静态映射,这对 opcache.preload 非常关键:preload 脚本里 require 的文件,必须是已知、稳定、无动态 require 的 PHP 文件。如果 autoload 未优化,classmap 可能缺失,或 PSR-4 映射依赖运行时解析,导致 preload 失败。
-
composer dump-autoload -o是必须步骤,确保所有类路径可静态推导 - 不要在 preload 脚本中调用
require_once __DIR__.'/vendor/autoload.php'—— 这会触发完整 autoloader 初始化,反而绕过优化逻辑,且可能引发 warning - preload 脚本应只
require具体的类文件(如App/Http/Kernel.php),或遍历 classmap 后require已知存在的 .php 文件
如何写一个安全的 preload.php 脚本(基于 Composer classmap)
直接硬编码 require 数百个文件不可维护。推荐从 vendor/composer/autoload_classmap.php 提取路径并过滤,再批量 require。注意:该文件返回的是关联数组,键为类名,值为绝对路径,且路径已存在(Composer 生成时已校验)。
/** * preload.php —— 建议放在项目根目录,由 php.ini 的 opcache.preload 指向 */ $classes = include __DIR__ . '/vendor/composer/autoload_classmap.php';// 只加载 app/ 和某些核心命名空间下的类,跳过测试、命令行、第三方私有类等 foreach ($classes as $class => $file) { if (strpos($class, 'App\') === 0 || strpos($class, 'Illuminate\') === 0 || strpos($class, 'Symfony\Component\HttpKernel') === 0) { if (is_file($file)) { require $file; } } }
- 不要无条件
require所有 classmap 条目 —— 第三方包可能含 side-effect 代码(如定义函数、扩展、register_shutdown_function) - 确保
$file存在且可读,避免 preload 失败导致整个 OPcache 禁用 - 该脚本在 PHP 启动时执行一次,不会经过 autoloader,所以不能依赖
class_exists或interface_exists
php.ini 中启用 opcache.preload 的关键配置
opcache.preload 必须指向一个**可被 PHP 主进程读取且语法正确**的 PHP 文件,且该文件不能依赖 $_SERVER、$_GET 等运行时超全局变量。常见错误是路径写错、权限不足、或 preload.php 中用了未声明的函数。
- 确认 OPcache 已启用:
opcache.enable=1、opcache.enable_cli=0(CLI 下无需 preload) - 设置 preload 路径:
opcache.preload=/path/to/your/project/preload.php,必须是绝对路径 - 加
opcache.preload_user=www-data(仅限 FPM 场景,指定加载用户,避免权限冲突) - 修改后必须重启 PHP-FPM 或 Apache,
php -v不会反映 preload 是否生效,要用php -r "var_dump(opcache_get_status()['preload']);"查看
验证 preload 是否生效及常见失败点
最直接方式是检查 OPcache 状态中的 preload 字段是否为 true,以及 scripts 列表是否包含你 require 的类文件。失败往往不是语法错,而是隐性依赖问题。
- preload 脚本中不能使用
__DIR__以外的魔术常量(如__FILE__在 preload 上下文可能为空) - 不能在 preload 中调用
extension_loaded()判断扩展 —— 此时扩展尚未完全初始化 - 若类中引用了未 preload 的 trait 或 interface,PHP 会报
Class XXX not found,即使它在 classmap 里 —— 因为 preload 是单次线性加载,不递归解析依赖 - 修改 preload.php 后,必须重启 PHP 进程;仅 reload 不会重新执行 preload
真正难的不是写几行 require,而是厘清哪些类可以安全地提前加载、哪些会因环境缺失而崩掉。建议从小范围开始(比如只 preload App\Http\Kernel 和几个核心服务),再逐步扩大,配合 opcache_get_status() 观察实际加载结果。










