
composer install 为什么没装 dev 依赖?
默认不装,因为 composer install 尊重 composer.lock 中记录的依赖状态——如果 lock 文件里没写 require-dev 的包,它就不会装。这常见于 CI/CD 或生产部署时手动删过 dev 依赖,或用 --no-dev 生成过 lock 文件。
实操建议:
- 本地开发想装全量(含
phpunit、mockery等),运行composer install前确认 lock 文件是完整生成的;如果 lock 丢了或不全,先composer update --lock再 install - CI 流水线里明确需要 dev 依赖(比如跑测试),必须加
--with-all-dependencies或直接用composer install --dev - 检查是否被环境变量干扰:
COMPOSER_NO_DEV=1会强制跳过 dev 包,哪怕命令写了--dev
composer install --dev 和 composer update --dev 有什么区别?
前者按 lock 文件“还原”已知版本,后者重新解析依赖树并更新 lock 文件——关键在是否改 lock。
实操建议:
- 团队协作中,
composer install --dev是标准流程:保证所有人装的 dev 包版本一致 -
composer update --dev只在你想升级某个测试工具(比如把phpunit从 9.5 升到 10.x)时用,但必须提交更新后的composer.lock - 别混用:
composer update --dev后又手动删了 lock 里的 dev 条目,下次install --dev仍不会装——lock 文件才是唯一权威
如何让生产环境彻底不装 dev 依赖?
靠 --no-dev 参数,但它不是“开关”,而是“指令覆盖”。只要执行时带上,Composer 就会跳过 require-dev 并从 lock 文件中剔除对应条目(如果 lock 里有)。
实操建议:
- 部署脚本里固定写
composer install --no-dev --optimize-autoloader,避免漏掉 -
--optimize-autoloader很重要:它生成 classmap,绕过 PSR-4 自动加载查找,减少生产环境文件 I/O - 注意:如果 lock 文件里压根没存 dev 包信息,
--no-dev实际没效果;真正起作用的是“锁文件内容 + 当前参数”的组合 - 验证是否生效:部署后进 vendor/ 目录看有没有
phpunit/或symfony/var-dumper/这类典型 dev 包目录
为什么 vendor/autoload.php 在 dev 和 prod 下行为不同?
autoload.php 本身没区别,区别在于 Composer 生成它的内容——dev 模式下会额外注册 autoload-dev 里的路径(比如 tests/),而 --no-dev 安装时这部分直接不写进 autoloader。
实操建议:
- 写测试时依赖
tests/下的辅助类?确保composer.json里有"autoload-dev": {"psr-4": {"Tests\": "tests/"}} - 上线后报
Class 'TestsTestCase' not found?基本就是--no-dev没加,或者 autoloader 没重建(加--optimize-autoloader可触发重生成) - 不要在生产代码里引用
autoload-dev下的类——它们不属于运行时契约,CI 通过不代表线上安全
最常被忽略的一点:lock 文件不是“快照”,而是“决议结果”。它既记录了 require,也记录了 require-dev ——但只有当你用 --dev 或没禁用 dev 时,Composer 才会读取其中的 dev 部分。删 lock、改参数、换环境变量,三者任意一个变动,都可能让依赖安装行为彻底偏离预期。










