结论:用 composer require --dev 安装的包仅写入 require-dev,部署时执行 composer install --no-dev 会跳过安装,若生产代码意外引用其类则报错 Class not found;加载与否取决于 autoload 配置,而非 --dev 标志本身。

直接说结论:用 composer require --dev 安装的包,只在开发环境生效,不会出现在生产环境的自动加载中 —— 但前提是部署时用了 composer install --no-dev。
为什么加 --dev 后包没进 autoload?
加 --dev 不影响自动加载逻辑本身,它只控制包是否写入 require-dev 区块。真正决定类能否被加载的,是 Composer 的 autoloading 配置(autoload 和 autoload-dev)是否包含该包的命名空间或路径。
-
composer require --dev phpunit/phpunit→ 写入require-dev,但 PHPUnit 自身的autoload是独立定义的,不影响你的项目类加载 - 如果你自己写的开发工具包(比如
myorg/stub-generator)也带autoload-dev配置,那它的类默认不参与主 autoloader,除非你手动合并或改用autoload - 常见误解:以为
--dev= “不加载”,其实是“不发布”,加载与否看 autoload 规则
composer require --dev 和 composer require 的实际差异
核心区别不在安装行为,而在 composer.json 的字段归属和后续部署行为:
- 不加
--dev:写入require,部署时即使加--no-dev也会保留 - 加
--dev:写入require-dev,运行composer install --no-dev时跳过安装,且vendor/autoload.php仍可用(只要包本身没被删)—— 但若该包提供运行时依赖(如某些测试基类被生产代码意外引用),就会报Class not found - 执行
composer update时,默认同时更新require和require-dev;加--no-dev则跳过require-dev中的包 -
composer dump-autoload默认同时处理autoload和autoload-dev,不受--dev标志影响
什么时候必须用 --dev?
不是“能用就用”,而是“该隔离才用”。典型场景包括:
- 仅用于测试的库:
composer require --dev phpunit/phpunit、composer require --dev myorg/test-helpers - 本地开发辅助工具:
composer require --dev laravel/pint、composer require --dev symfony/var-dumper(后者虽常被开发中直接调用,但生产应禁用) - CI/CD 流程依赖:
composer require --dev dealerdirect/phpcodesniffer-composer-installer,这类包绝不该出现在线上vendor/ - 反例:不要给
monolog/monolog加--dev,哪怕你只在本地 log —— 它是运行时日志组件,属于require
容易忽略的坑:require-dev 包被生产代码意外依赖
最隐蔽的问题不是安装失败,而是“看似正常,上线后崩”。例如:
// 在某个服务类里写了:
use MyOrg\DevOnly\StubBuilder;
class UserService
{
public function create()
{
return (new StubBuilder())->build();
}
}
这个类如果被生产逻辑调用,而 MyOrg\DevOnly\StubBuilder 只在 require-dev 里,上线执行 composer install --no-dev 后,vendor/ 里根本没这个包,直接 Class not found。
解决办法只有两个:
– 把该类移到 tests/ 或 dev-tools/ 目录,并确保不被生产 autoloader 扫描
– 或者把包移到 require,并用条件逻辑控制功能开关(比如检查 APP_ENV !== 'production')
别指望靠 Composer 自动帮你拦住这种耦合 —— 它只管装包,不管你怎么用。










