--optimize-autoloader在PHP 7.4+和Composer 2.x下非默认提速项,用错反拖慢冷启动;真正有效组合是--no-dev+--prefer-dist+--classmap-authoritative,且须严格清理autoload配置。

classmap 在 PHP 7.4 + Composer 2.x 下不是默认提速项
直接说结论:--optimize-autoloader(即 -o)在 PHP 7.4+ 和 Composer 2.x 环境下,不会自动提升 classmap 性能,反而可能拖慢冷启动。它生成的 vendor/composer/autoload_classmap.php 是一个全量反序列化数组,常达数 MB;而一次 HTTP 请求实际只用到其中不到 5% 的类。Composer 2 已默认启用更轻量的 autoload_static.php,它是预编译静态映射,OPcache 友好,-o 对它无效,还可能干扰其加载。
真正要生成有效 classmap,必须显式声明 classmap 字段
composer dump-autoload -o 不会扫描未在 composer.json 中声明的路径——哪怕你目录里全是合法类文件。纯静态类、无命名空间文件(如 helpers.php、Database.php)或 legacy 目录,必须手动写进 autoload.classmap:
{
"autoload": {
"psr-4": {
"App\": \"app/\""
},
"classmap": ["app/", "lib/utils/", "src/legacy/"]
}
}
然后执行:
-
composer dump-autoload -a:强制递归扫描每个.php文件,提取class/interface/trait声明,写入autoload_classmap.php - 别只用
-o:它不触发扫描,只优化已注册的 PSR-4 映射(转为autoload_static.php) - 删掉
"tests/": ["tests/"]这类配置:它们会让-a白扫几百个文件,膨胀 classmap
--classmap-authoritative 不是开关,是契约
启用 --classmap-authoritative 后,Composer 会完全跳过 PSR-4 动态查找逻辑,只查 autoload_classmap.php。但它生效有硬性前提,漏一条就静默报 Class not found:
立即学习“PHP免费学习笔记(深入)”;
-
composer.json中不能有"files"条目(如全局函数文件),否则这些文件不会进 classmap,又因 authoritative 模式被跳过加载 - 所有类路径必须严格符合 PSR-4 规则:命名空间末尾带反斜杠(
"App\":)、目录结构与命名空间层级完全一致、大小写敏感(Linux 上尤其致命) -
autoload-dev必须和autoload完全分离;生产部署时一定要加--no-dev,否则测试类混入主映射,导致 fallback 触发 - 私有包需在
composer.json中声明"archive": {"exclude": ["/tests", "/docs"]},否则 Satis 构建时污染 classmap 扫描范围
验证 classmap 是否真生效,别信命令是否跑过
执行完 composer dump-autoload -a --classmap-authoritative 后,必须验证两件事:
- 运行
php -r "var_dump(require 'vendor/composer/autoload_classmap.php');",搜索你的类名(如'MyHelper'),确认有对应路径 - 运行
php -r "var_dump(class_exists('MyHelper'));",返回true才算成功;若为false,常见原因是类文件里用了eval()、动态类名拼接($class = $prefix . $name)或匿名类,这些会被-a跳过 - 检查
vendor/autoload.php是否含'classmap-authoritative' => true;再打开vendor/composer/autoload_real.php,搜索findFile方法——如果只剩if ($classMap = $this->classMap)分支,且没有foreach ($this->prefixesPsr4相关代码,说明已彻底禁用动态查找
最易被忽略的是:classmap 模式下,spl_autoload_register 手动注册的加载器、class_exists("{$prefix}".$name) 这类动态逻辑会完全失效——这点在 Laravel 的 Service Provider 或条件加载场景中极易踩坑。



















