正确写法是 composer require 包名 --dev,它将包写入 require-dev 并仅在未加 --no-dev 时安装;误加到 require 需删 vendor 和 composer.lock 后重装。

composer require 只装 dev 依赖的正确写法
加包时默认会写进 require,导致上线环境也强制安装——这不是你想要的。必须显式指定它属于开发阶段,否则 CI 构建或生产部署可能失败,或者引入不必要的安全风险。
用 --dev(或短写 -d)参数,它会把包写入 require-dev 区域,并且只在 composer install 未加 --no-dev 时才安装:
composer require phpunit/phpunit --dev
- 不加
--dev:包进require,生产环境也会被拉下来 - 已误加进
require?删掉vendor/和composer.lock,再用--dev重装 -
composer update默认包含require-dev,除非你加了--no-dev
如何让某些 dev 包在生产环境彻底不加载
仅靠 require-dev 不够。如果包里有自动注册的类、服务提供者或 autoload-dev 的 PSR-4 映射,它们仍可能被 autoloader 扫描到,尤其当测试文件混在 src 目录下时。
关键控制点有两个:
-
autoload-dev里的路径不会进入生产 autoloader,务必把测试类、fixture、命令行工具等放在这里 - Laravel、Symfony 等框架的 service provider 通常在
config/app.php或config/dev中按环境条件注册,别直接在主配置里无条件启用 - 检查包自身是否带
autoload配置——有些包(比如laravel/pint)根本不该出现在运行时 autoloader 中,它只是个 CLI 工具
require-dev 包引发的常见错误现象
这些报错往往让人误以为是代码问题,其实是环境错配:
-
Class 'PHPUnit\Framework\TestCase' not found:本地跑测试正常,但线上 CI 报这个——大概率是phpunit被误装进require,而 CI 执行了--no-dev -
Target class [FooCommand] does not exist(Laravel):命令类放在app/Commands但没加 autoload 映射,或它被注册在AppServiceProvider里却没做app()->environment('local', 'testing')判断 -
Failed to load class "Doctrine\ORM\Tools\Console\ConsoleRunner":Doctrine 的 console 工具被当成运行时依赖加载,其实它只该在bin/console中按需 require
区分环境的 require-dev 实操建议
不是所有 dev 包都适合全局 require-dev。有些只在特定环节需要,比如静态分析、格式化、安全扫描——它们不该参与 CI 测试阶段的依赖解析。
推荐分层管理:
- 基础 dev 工具(
phpunit,mockery,phpstan)放根composer.json的require-dev - CI 专用工具(
php-cs-fixer,psalm,security-checker)改用composer create-project或tools目录独立安装,避免污染主项目依赖树 - 本地开发辅助(
laravel/sail,symfony/cli)不要进require-dev,它们不是“包依赖”,而是 CLI 封装器
最常被忽略的一点:.gitignore 里漏掉 vendor/bin/*,结果把 phpunit 的软链接提交了,导致不同系统行为不一致。










