生产环境必须用 composer install --no-dev --optimize-autoloader;若误用 dump-autoload -o,会导致 autoload_classmap.php 未更新、体积为0或异常。

生产环境必须用 composer install --no-dev --optimize-autoloader,不是 dump-autoload -o
绝大多数线上性能问题,根源就在这条命令写错了。你执行 composer dump-autoload -o 后发现 vendor/composer/autoload_classmap.php 没更新、体积为 0 或只有 <?php return array();,说明它根本没触发 classmap 重建——因为 Composer 2.x 的 classmap 只在 install 或 update 阶段生成,dump-autoload 默认只刷新 autoload_static.php 和 PSR-4 映射,不扫描文件、不校验路径、不写入 classmap。
常见错误现象:
-
dump-autoload -o后首次请求仍慢,strace显示大量stat("/vendor/.../SomeClass.php")失败 -
autoload_classmap.php达到几 MB,但实际只用到其中不到 5% 的类,每次请求全量 require 进内存反而更慢 - CI/CD 流水线里只跑
dump-autoload -o,但没装新包,新依赖里的类根本不在 classmap 中
正确做法:
- 部署脚本中固化:
composer install --no-dev --optimize-autoloader --no-interaction --prefer-dist - 确保该命令在目标机器(或相同 PHP 版本+扩展环境)上执行,避免
realpath差异导致 classmap 失效 -
"optimize-autoloader": true写在composer.json里只是默认开关,不触发任何实际动作
--classmap-authoritative 开了就报 Class not found?先查 classmap 是否漏类
这个参数不是“加速开关”,而是“断言模式”:类不在 autoload_classmap.php 里就直接抛错,不再 fallback 到 PSR-4 拼路径或 file_exists() 查找。所以报错不是配置错了,是 classmap 本身不完整。
常见漏类原因:
-
composer.json中"psr-4": {"App\": "app/"}缺末尾反斜杠(应为"App\"),命名空间扫描失败 - 新增类文件后没重新运行
install,dump-autoload -o不感知文件增删或移动 - 误把
tests/、docs/、examples/路径写进了autoload.psr-4或autoload.classmap,挤占有效空间,导致真实类被跳过 - 用了
"files"类型加载(如"app/Helpers/functions.php"),这类文件不会进 classmap,开了--classmap-authoritative后仍能工作,但别误以为所有 autoload 都走 classmap
验证方式:
- 打开
vendor/composer/autoload_classmap.php,搜索你要用的类名(如AppConsoleCommandsDeployCommand) - 检查
vendor/autoload.php是否包含'classmap-authoritative' => true
为什么 --no-dev 必须和 --optimize-autoloader 一起用
单独用 --no-dev 只是跳过安装 require-dev 包,但不会清理已注册的 autoload 规则;单独用 --optimize-autoloader 会把 dev 包里的测试类、Mock 类、文档示例一并扫进 classmap,导致数组体积暴涨(常达 2–5 MB),徒增反序列化开销和内存占用。
典型污染场景:
- 某个包在
autoload-dev里声明了"Tests\": "tests/",不加--no-dev就会把这些路径保留在autoload_psr4.php中,甚至混进 classmap -
phpunit、fakerphp/faker、larastan等 dev-only 包的类被塞进 classmap,但线上完全用不到
实操建议:
- 把所有测试相关 autoload 配置统一挪到
autoload-dev块,而非autoload - CI/CD 构建阶段务必先
git checkout到目标 tag/branch,再执行composer install --no-dev --optimize-autoloader,防止composer.lock和代码版本不匹配 - 若团队曾忽略提交
composer.lock,部署时可能 fallback 到composer update,破坏可重现性
opcache 和 preload 不是可选项,而是生效前提
即使 autoload_classmap.php 生成正确,若没配好 opcache,优化几乎白做。PHP-FPM 下,opcache.enable_cli=1 必须开启,否则 autoload_classmap.php 每次请求都重新解析,比不优化还慢。
opcache.preload 是更高阶的绕过方案,但它有硬限制:
- preload 文件里只能用
require或include,禁止class_exists()、new等运行时逻辑 - 不要 preload 整个 vendor 目录,应精确列出高频核心类(如
LaravelIlluminateFoundationApplication) - preload 脚本写错会导致 PHP-FPM 启动失败,调试成本高
验证是否真正生效:
- 用
strace -e trace=stat,openat php -r "new AppHttpControllerHome();"观察是否还有大量stat()调用 - 检查
vendor/autoload.php是否含$loader->addClassMap(require __DIR__ . '/composer/autoload_classmap.php'); - 确认
autoload_classmap.php非空且体积合理(小项目几百 KB,大项目几 MB 正常)
最常被忽略的一点:classmap 优化不是“越大越好”,而是“越准越好”。删掉无用 autoload 配置(比如 "docs/": ["docs/"]、"lega/": ["legacy/"])比加一堆 -o 参数管用得多。



















