Composer 不提供预加载能力,仅生成安全的类路径清单供 PHP 8.0+ opcache.preload 使用;因 vendor/autoload.php 含动态逻辑,不可直接预加载,须用 composer dump-autoload --classmap-authoritative --no-dev 生成绝对路径 require_once 列表,并严格过滤命名空间与副作用文件。

Composer 本身不提供“预加载”能力,所谓包的预加载,实际是让 PHP 在启动时就把类文件编译进 opcache,跳过运行时的文件读取和解析。这必须靠 PHP 8.0+ 的 opcache.preload 配置驱动,而 Composer 只负责帮你生成一份可信、安全、可静态 require 的类路径清单。
为什么不能直接 require vendor/autoload.php 到 preload.php
因为 vendor/autoload.php 含大量动态逻辑:闭包注册、环境判断、if 分支、ClassLoader::loadClass() 调用等。PHP 启动时执行它会报错,典型错误是:Cannot preload class ... because it was already defined 或 Cannot declare class, because the name is already used。preload 脚本要求纯静态、无副作用、无运行时依赖。
- 不能有
if/foreach动态遍历目录 - 所有
require_once必须是绝对路径(不能拼__DIR__ . '/..' . $path) - 不能调用未定义函数(比如
opcache_compile_file()在 preload.php 里不可用) - 不能包含任何含
define()、function_exists()、register_shutdown_function()的第三方类文件
怎么从 Composer 获取安全可用的类路径列表
核心是用 composer dump-autoload --classmap-authoritative --no-dev 生成权威 classmap,再从中筛选出你真正想预加载的类。生成的 vendor/composer/autoload_classmap.php 是一个纯数组,结构为 ['App\Http\Controller' => 'src/Http/Controller.php'],值是相对路径 —— 你需要把它转成绝对路径,并过滤掉风险项。
- 只保留项目源码命名空间,例如
App\、Domain\、Infrastructure\;跳过Tests\、Command\、Console\ - 排除第三方包中含 side-effect 的文件(如 Laravel 的
Illuminate/Foundation/Testing/TestCase.php会定义全局函数) - 不要用
--apcu:它只优化运行时查找,不产出文件路径,对 preload 无用 - 检查生成结果:
wc -l vendor/composer/autoload_classmap.php应该是几千行,几百行说明扫描目录没配对
preload.php 怎么写才稳定不崩
最终的 preload.php 必须是一份“硬编码”的 require_once 列表,路径全为绝对路径,且顺序合理(父类先于子类)。不要试图在脚本里 include classmap 再循环 —— 这属于动态逻辑,PHP 启动时禁止。
立即学习“PHP免费学习笔记(深入)”;
- 推荐用工具生成,比如
spiral/preload:运行vendor/bin/preload --config=preload.php,它会按composer.json的autoload和autoload-dev规则解析并输出干净列表 - 手动写也行,但得逐行写死:
require_once '/var/www/app/src/Http/Response.php'; - 路径必须真实存在且可读,PHP 用户(如 www-data)要有权限读取,否则启动失败
- 避免预加载大文件(如生成的
bootstrap/cache/config.php),opcache 内存可能溢出,可通过opcache.memory_consumption调整
验证预加载是否生效的三个关键点
光写对 preload.php 不够,还要确认 PHP 真正加载并缓存了它。最容易被忽略的是配置和权限链路断裂。
-
php.ini中必须启用:opcache.enable=1、opcache.preload=/var/www/app/preload.php、opcache.preload_user=www-data(若非 root 运行) - 重启 PHP-FPM 或 Apache 后,执行
php -i | grep preload,确认输出中有opcache.preload => /var/www/app/preload.php - 运行
php -r "print_r(opcache_get_status()['preload_statistics']);",看scripts_preloaded数量是否增长,且preload_script字段显示你的脚本路径 - 线上请求后查
opcache_get_status()['scripts'],确认关键类文件(如src/Http/Controller.php)已在缓存中,timestamp不为 0
最常卡住的地方不是代码怎么写,而是 preload.php 的路径权限、opcache.user 配置缺失、或 classmap 没过滤干净第三方副作用文件 —— 这些问题不会报错,只会让预加载静默失效。



















