默认会装dev依赖——只要composer.json含require-dev且未加--no-dev等限制参数,install即全量安装;常见错误是误将dev包写入require导致生产环境缺失。

composer install 默认装不装 dev 依赖?
默认会装——只要 composer.json 里有 require-dev,且没加任何限制参数,composer install 就照单全收。这不是“开发环境才装”,而是“不明确说不装,就全装”。
常见错误现象:phpunit 在本地能跑测试,上线却报 Class not found——十有八九是部署脚本漏了 --no-dev,但更隐蔽的根因是:你当初写 composer require phpunit/phpunit 没加 --dev,结果它进了 require,变成生产依赖;而线上又执行了 --no-dev,导致连带误删(实际是根本没装上)。
-
composer require phpunit/phpunit --dev→ 正确,写入require-dev -
composer require phpunit/phpunit→ 错误,写入require,污染生产依赖树 - CI 跑测试时,用
composer install --dev或什么都不加(默认行为),确保测试工具版本和composer.lock一致
为什么 --no-dev 有时还是装了 dev 包?
不是参数失效,是 composer.lock 文件“带货”了——它记录了上次 composer update 时所有包(含 dev)的精确版本与哈希值。composer install --no-dev 只跳过 autoload 和部分解压逻辑,但若 lock 文件里有 packages-dev 字段,某些包仍可能被解压进 vendor/(尤其旧版 Composer)。
检查方法:composer show --dev(本地)或直接打开 composer.lock 搜 "packages-dev"。
- 修复方式:CI 中先运行
composer update --no-dev --lock,再提交更新后的composer.lock - 部署前务必清空
vendor/:rm -rf vendor/,否则残留旧包会干扰一致性 - 别信
COMPOSER_NO_DEV=1:它对整个 shell 子进程生效,Docker 调试时容易误伤,显式写--no-dev更可控
生产部署只用 --no-dev 还不够
--no-dev 只控制“装不装”,不控制“怎么加载”和“是否校验”。生产环境真正要的是:轻、快、稳。
- 必须加
--optimize-autoloader:生成 classmap,绕过 PSR-4 动态查找,减少文件 I/O - 必须加
--no-interaction:防止卡在信任仓库提示(如私有 Packagist) - 严禁用
composer update --no-dev:它会重算依赖、改composer.lock,破坏锁定——生产只允许install - 验证是否生效:部署后进
vendor/看有没有phpunit/或symfony/var-dumper/目录
autoload-dev 和 --no-dev 的关系是什么?
autoload-dev 是配置,--no-dev 是开关。两者配合才完整:没有 autoload-dev,测试类路径不会注册;开了 --no-dev,即使写了 autoload-dev,Composer 也不会把它写进 vendor/autoload.php。
典型翻车现场:你在 tests/Helper.php 里写了 class Helper {},并在 composer.json 里配了:"autoload-dev": {"psr-4": {"Tests\": "tests/"}}。但部署时用了 --no-dev,结果代码里 new TestsHelper() 直接报错——因为自动加载规则根本没生成。
- 解决方案:测试辅助类尽量不硬编码调用;或把通用工具类移到
autoload(非 dev)下 -
vendor/autoload.php本身无区别,区别全在内容:dev 模式下多注册了autoload-dev路径 - 别指望靠环境变量动态切 autoload,Composer 不支持运行时切换
--no-dev 不等于“生产安全”,它只是第一步。真正决定线上稳定性的,是 composer.lock 是否干净、vendor/ 是否干净、以及 PHP 版本和扩展是否和 config.platform 对齐——三者缺一不可。










