生产环境必须用 composer install --no-dev --optimize-autoloader --classmap-authoritative,且确保 composer.lock 由 composer update --no-dev --lock 生成,同时清理 autoload-dev 和 dev 插件,才能彻底排除 dev 依赖加载风险。

生产环境部署时,composer install 默认仍会装 require-dev 里的包,除非你显式告诉它别装——这不是 bug,是设计如此。
为什么 composer install 还是装了 dev 依赖?
Composer 默认行为是「按 composer.lock 安装所有已锁定的包」,不管当前环境是不是生产。哪怕你删了 require-dev 段,只要 composer.lock 里还记着那些 dev 包,install 就照装不误。
-
composer install不读composer.json的require-dev是否存在,只认lock文件记录 -
--no-dev是唯一能跳过 dev 包安装的开关,但它不会从lock中剔除它们——下次没加这个参数就又装回来 - CI/CD 流水线里漏掉
--no-dev,上线后可能意外带上phpunit、faker等非运行时必需包
composer install --no-dev 必须加,但还不够
加 --no-dev 能跳过安装,但前提是 composer.lock 本身不含 dev 包的依赖树——否则某些插件(比如 composer-plugin 类)可能在 install 阶段提前触发 autoload 逻辑,间接加载 dev-only 的类。
- 上线前先执行
composer install --no-dev --dry-run,确认输出里没有 dev 包的安装动作 - 更稳妥的做法:在 CI 构建阶段用
composer install --no-dev --optimize-autoloader --classmap-authoritative -
--optimize-autoloader生成扁平 classmap,避免运行时扫描vendor/autoload.php加载 dev 目录下的文件 -
--classmap-authoritative强制只走 classmap,彻底绕过 PSR-4 自动发现——这对防止 dev 类被意外加载很关键
如何让 composer.lock 彻底不含 dev 依赖?
靠删 require-dev 并不能清理 lock 文件。必须重新生成 lock,且确保生成时没加载任何 dev 包。
- 先删掉
composer.lock和vendor/ - 临时注释或清空
composer.json中的require-dev块 - 运行
composer update --no-dev --lock(注意不是install) - 此时生成的
composer.lock不含 dev 包的 hash、版本、autoload 信息,后续composer install --no-dev才真正干净 - 别忘了把
require-dev写回去(开发机上需要),但 lock 文件保持“生产专用”分支
容易被忽略的坑:autoload 和插件残留
即使没装 dev 包,如果 autoload-dev 在 composer.json 里声明了路径,且项目代码里有 class_exists('SomeTestHelper') 这类调用,PHP 可能因 autoloader fallback 机制尝试加载不存在的类——报错或触发 warning。
- 检查
composer.json的autoload-dev段,生产构建前可临时删掉或用脚本注释 - 某些插件(如
hirak/prestissimo)在旧版 Composer 中会在install前预加载配置,导致 dev 插件也被初始化——升级到 Composer 2.2+ 可缓解 -
vendor/autoload.php本身不区分环境,所以最终得靠--classmap-authoritative+--no-dev双保险封死入口
dev 依赖不是“装不装”的问题,而是“会不会被加载、能不能被发现”的问题。锁文件、autoloader 模式、插件生命周期,三个地方都得卡死,才真正算落地。










