composer require-dev 将包安装到 require-dev 而非 require,生产环境执行 composer install --no-dev 时不会安装,适用于 PHPUnit 等仅开发阶段需要的工具。

composer require-dev 会把包装进 dev-dependencies 而非 dependencies
这是最核心的区别:用 composer require-dev 安装的包,只会出现在 composer.json 的 "require-dev" 字段里,不会进入 "require"。这意味着这些包在生产环境(composer install --no-dev)下根本不会被安装,也不会被打包进最终部署产物。
典型适用场景包括:phpunit/phpunit、mockery/mockery、phpstan/phpstan、friendsofphp/php-cs-fixer 等——它们只在本地写测试、跑 CI、做静态分析时需要,上线后毫无作用。
如果你误用 composer require 装了测试包,它会混进 "require",导致生产环境多装一堆无用依赖,还可能引发冲突或安全扫描告警。
安装时加 --dev 参数和不加的区别
composer require-dev 是命令别名,等价于 composer require --dev。两者行为完全一致,只是写法偏好不同。但注意:没有 composer require-dev --no-dev 这种组合,后者会报错。
-
composer require-dev phpunit/phpunit→ 写入"require-dev",默认安装最新稳定版 -
composer require-dev phpunit/phpunit:^9.6→ 指定版本约束,推荐显式写明,避免 CI 环境因版本漂移失败 -
composer require-dev --with-all-dependencies phpunit/phpunit→ 强制连同其所有依赖(含可能本该是 dev 的间接依赖)一起进require-dev,慎用;多数情况不需要
require-dev 包在生产环境会被自动跳过
只要部署时执行的是 composer install --no-dev(Laravel Forge、Envoyer、大多数 CI/CD 流水线默认行为),require-dev 下的所有包及其依赖都不会被下载、解压、autoload。这能显著缩短部署时间、减小容器镜像体积、降低攻击面。
验证方式很简单:
composer install --no-dev ls vendor/ | grep phpunit # 应该什么也不输出
如果发现 vendor/phpunit 还在,说明要么没加 --no-dev,要么有人手动改过 composer.json 把它挪到了 require 里。
require-dev 和 autoload-dev 的配合容易被忽略
仅把包放进 require-dev 不够——如果这个包提供了测试专用的辅助类(比如自定义 PHPUnit TestCase、测试用的 Service Provider),你还得确保它们能被自动加载。这时要检查 composer.json 的 "autoload-dev" 段:
{
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
}
否则即使包装好了,new Tests\TestCase() 也会报 Class not found。常见疏漏点:
- 忘记运行
composer dump-autoload(尤其是改完autoload-dev后) - 路径写错,比如写成
"Tests\\": "test/"(少了个s) - 用了
classmap但没包含新测试目录,也没重新生成映射
开发阶段建议始终保留 autoload-dev 配置,并定期 composer dump-autoload -o 优化自动加载性能。










