Composer require --dev 仅修改 composer.json 的 require-dev 字段,不控制运行时行为;是否安装 dev 依赖取决于 composer install/update 是否使用 --no-dev 参数。

Composer 本身没有“环境感知”的依赖安装机制,composer require --dev 只是把包写入 require-dev 字段,并不自动控制它在生产环境是否被加载或安装——能否生效,完全取决于你是否执行了 --no-dev。
为什么 composer require --dev 不等于“只在开发环境生效”
这个命令只是修改 composer.json 中的 require-dev 区块,不会改变运行时行为。真正决定开发依赖是否被安装、是否被自动加载的,是后续的 composer install 或 composer update 是否加了 --no-dev 参数。
-
composer install(无参数)→ 安装require和require-dev中所有包 -
composer install --no-dev→ 只安装require中的包,跳过require-dev -
composer dump-autoload默认也会为require-dev生成自动加载规则,除非加--no-dev
如何确保生产环境不装 dev 依赖
关键不是怎么加依赖,而是部署时怎么装依赖。CI/CD 或生产服务器上必须显式使用 --no-dev,否则 require-dev 的包照样会装进去,甚至可能因冲突或安全问题引发故障。
- 部署脚本里写死:
composer install --no-dev --optimize-autoloader --no-interaction - Dockerfile 中避免用
composer install(无参),改用带--no-dev的完整命令 - 检查
composer.lock:如果它包含 dev 包的条目,说明上次install/update没加--no-dev,需清理后重装 - PHP 自动加载不受
--no-dev影响——只要类文件存在且被 autoload 规则覆盖,就能被加载(哪怕它是 dev 包里的)
require-dev 包在生产环境仍可能“起作用”的常见场景
很多开发者以为加了 --no-dev 就万事大吉,但以下情况会让 dev 依赖意外生效:
- 某些包(如
phpunit/phpunit)的类被项目代码直接require或include,而非通过 autoloader 加载 → 即使没安装,运行时也会 fatal error;但若误把测试工具逻辑混进生产路由,就可能触发 - 配置文件中硬编码调用了 dev 包的类(例如 Laravel 的
phpunit.xml或 Symfony 的test/bootstrap.php被误引入) - 使用了
composer create-project初始化项目,默认会装 dev 依赖,需手动补--no-dev -
autoload-dev中定义的路径,即使没装 dev 包,只要目录存在,也可能被扫描到(尤其配合classmap或files类型)
{
"require": {
"monolog/monolog": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"symfony/var-dumper": "^5.0"
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
}
真正需要环境隔离的依赖(比如不同数据库驱动、Mock 工具、调试面板),不能只靠 require-dev 控制——得结合条件加载逻辑(如 if (APP_ENV === 'dev'))、容器服务注册开关,或者用 config/packages/dev/ 这类框架级机制。Composer 的 --dev 是安装开关,不是运行时开关。










