composer autoload 本身不支持预加载,真正实现预加载需 php 8.0+ 配合 opcache.preload 配置;需通过 composer dump-autoload --classmap-authoritative 生成类映射,并在 preload.php 中按依赖顺序 require 绝对路径类文件,且须确保 opcache 配置正确、用户权限匹配、内存充足。

composer autoload 本身不支持预加载,得靠 PHP 8.0+ 的 opcache.preload
Composer 的 autoload 只是注册自动加载器(spl_autoload_register),类文件在首次使用时才读取、解析、编译。它本身没有“预加载”能力——所谓“预加载类”,实际是让 PHP 在启动时就加载并编译好一批脚本,进 opcache 内存,跳过运行时的文件 I/O 和编译开销。
真正起作用的是 PHP 配置项 opcache.preload,它要求你写一个 preload 脚本,显式 require 那些核心类文件。Composer 不参与这个过程,但它能帮你生成“该预加载哪些文件”的清单。
- PHP 版本必须 ≥ 8.0,且
opcache.enable=1、opcache.preload指向有效脚本 - preload 脚本里不能有动态逻辑(如
if判定环境)、不能调用未定义函数,否则 PHP 启动失败 - Composer 自动生成的
vendor/autoload.php不能直接 preload——它含大量条件判断和闭包,会触发 “Cannot preload class … because it was already defined” 错误
怎么生成安全可 preload 的类列表?用 composer dump-autoload --apcu 或 --classmap
目标是拿到一份“纯类定义文件”的绝对路径列表,且确保它们彼此无依赖冲突。最稳妥方式是用 Composer 的 classmap 生成机制,配合手动筛选:
-
composer dump-autoload --classmap-authoritative --no-dev:生成权威 classmap(跳过 PSR 自动发现),输出到vendor/composer/autoload_classmap.php - 该文件是纯数组映射,不含逻辑,但值是相对路径;需结合
vendor/composer/autoload_static.php或自己拼接__DIR__ . '/..' . $path - 不要用
--apcu,它只优化运行时查找,不产出文件路径,对 preload 无用 - 避免 include 所有类:第三方包里可能含 CLI 工具类、命令行入口、条件 define,preload 时执行会报错或污染全局状态
示例片段(用于生成 preload.php):
foreach (require __DIR__ . '/vendor/composer/autoload_classmap.php' as $class => $file) {
$absPath = __DIR__ . '/vendor/' . ltrim($file, '/');
if (str_starts_with($class, 'App\') || str_starts_with($class, 'MyLib\')) {
require $absPath;
}
}
opcache.preload 脚本里 require 类文件的顺序很重要
PHP preload 是单次线性执行,如果 A 类继承 B 类,但 B 还没被 require,就会报 Class 'B' not found。而 classmap 数组本身不保证继承顺序。
- 不能直接 foreach classmap 数组——必须先拓扑排序:提取每个文件的
use和extends,构建依赖图 - 实践中更简单:优先 require
src/下的核心领域类(Entity、Service、Repository),再 requirevendor/中明确稳定的库(如symfony/polyfill),跳过bin/、Tests/、Command/ - 遇到
Cannot declare class X, because the name is already used,说明某类被重复 require(比如两个包都导出了同名 interface),要从列表中剔除其中一个 - 每次改代码后,必须重启 PHP-FPM / Apache,否则新类不会进 preload
别忽略 opcache 配置细节,否则 preload 形同虚设
即使写了完美的 preload.php,若 opcache 配置不对,PHP 也不会执行它,或执行了但没效果。
-
opcache.preload必须是绝对路径(如/var/www/myapp/preload.php),相对路径无效 -
opcache.preload_user必须设置为运行 PHP 的用户(如www-data),否则权限不足导致 preload 失败且无日志 -
opcache.memory_consumption要足够大——preload 的文件越多,占用越大;默认 128M 很容易不够,建议 256M 起 - 检查是否生效:
php -i | grep preload应显示 “opcache.preload => /path/to/preload.php”;再看opcache_get_status()['preload_statistics']是否有非空scripts数组
最常被忽略的一点:preload 只对 CLI 和 FPM 主进程生效,不是每个请求都重跑。所以它提升的是“首个请求之后所有请求”的性能,但调试阶段看不到“第一次变快”,反而可能因 preload 失败导致整个服务起不来——务必先在 staging 环境验证 preload.php 的健壮性。











