composer dump-autoload 越跑越慢是因为全量扫描 vendor 中未规范配置 PSR-4 的包及混入测试文件的目录,导致 autoload_classmap.php 膨胀、PHP 加载解析耗时剧增。

composer dump-autoload 为什么越跑越慢
因为默认生成的 autoload_classmap.php 是全量扫描,vendor 里每个包只要带 classmap 或没声明 psr-4,就会被扫进一张大数组。包一多、文件一杂(比如测试文件混在 src 里),这个文件就膨胀得厉害,PHP 加载时要一次性读入并解析整张映射表。
- 检查是否误把
tests/目录加进了autoload.classmap或没排除在autoload-dev外 - 运行
composer dump-autoload -o(即--optimize)会合并为一张静态数组,但前提是所有 autoload 配置都合规;否则它会悄悄退化成非优化模式,还不报错 - 用
composer show --profile看 dump 阶段耗时,如果 >500ms,大概率有路径污染或循环依赖导致反复扫描
psr-4 比 classmap 快,但写错命名空间就白搭
psr-4 是按需加载,不匹配就不查,理论上比 classmap 轻量得多。但它对目录结构和命名空间一致性极其敏感——差一个字母、大小写不对、末尾多一个反斜杠,类就永远找不到,还可能 fallback 到慢的 files 或全量扫描。
- 确保
composer.json里autoload.psr-4的 key 是带结尾反斜杠的完整命名空间,例如"App\\": "src/",不是"App"或"App\\"(少斜杠) - 目录名必须严格匹配命名空间小写形式:如果写的是
"MyVendor\\Http\\": "lib/Http/",那lib/Http/Client.php里就必须是namespace MyVendor\Http;,不能是myvendor\http - Windows 下大小写不敏感容易掩盖问题,上线前务必在 Linux 环境验证一次
php -r 'var_dump(class_exists("MyVendor\Http\Client"));
dev 依赖不该进生产 autoload
autoload-dev 里的规则(比如测试类映射)默认也会被 dump-autoload 打包进去,除非你明确告诉 Composer:生产环境不需要它们。
- 部署时始终加
--no-dev:例如composer install --no-dev --optimize-autoloader - 检查
vendor/composer/autoload_psr4.php,确认里面没有你项目测试目录的映射项;如果有,说明autoload-dev被错误地继承到了主 autoload 块里 - 某些包(如
phpunit/phpunit)自身声明了autoload-dev,但它的autoload主体很干净——这类不用管;真正要盯的是你自己项目根composer.json里写的autoload-dev
require vs require-dev 对 autoload 的隐性影响
表面上只是依赖范围区别,实际上会影响 autoloader 生成逻辑:只要某个包出现在 require-dev,它的 autoload 规则仍会被扫描并合并进来,哪怕你从没 use 它的类。
- 运行
composer depends --tree phpunit/phpunit查哪些包间接拉进了重型 dev 工具(比如symfony/var-dumper在 dev 里,但被phpunit依赖,结果它的autoload也被加载了) - 如果某个 dev 包只用于命令行脚本(如
larastan),考虑改用composer global require隔离,避免污染项目 autoload -
composer dump-autoload --apcu可缓存映射到 APCu,但前提是 PHP 启用了 APCu 且未设apc.enable_cli=0;CLI 环境下常被忽略这点
autoload 性能瓶颈往往不在代码里,而在 composer.json 的一个斜杠、一次忘记 --no-dev、或者开发机和线上环境的大小写容忍差异。调优不是堆参数,而是让每条 autoload 规则都可预测、可验证、可剥离。











