composer require --dev 会完整重生成 composer.lock,重新解析全部依赖而非仅修改 require-dev;手动编辑 composer.json 后需显式运行 install 或 update,且 dev 包信息始终存在于 lock 文件中。

require --dev 会触发 lock 文件的完整重生成
执行 composer require --dev 不只是往 composer.json 的 require-dev 区块加一行,它会立即运行依赖解析器,重新计算整个依赖图(包括 require 和 require-dev),然后重写 composer.lock —— 即使你只加了一个小工具包,也可能导致几十个包的版本微调(比如从 ^2.1.0 锁定到 2.1.3 或回退到 2.0.9)。
常见错误现象:
• 本地 composer.json 手动加了 "phpunit/phpunit": "^10.5",但没运行 composer install,CI 构建失败(因为 composer.lock 里没这条记录)
• 团队成员各自手动改 composer.json 后直接 git commit,结果 composer.lock 没同步更新,合入后 CI 报 “package not found”
-
composer require --dev是原子操作:修改 JSON + 解析依赖 + 更新 LOCK - 手动编辑
composer.json只是“声明意图”,不改变实际安装状态 - 后续必须显式运行
composer install或composer update才能生效(且行为不同,见下一条)
手动改 composer.json 后该用 install 还是 update?
关键区别在于是否信任现有 composer.lock:
- 如果只是追加一个新 dev 包,且确认其他依赖版本无需变动 → 用
composer install(它会严格按lock安装,**不会**重新解析依赖) - 如果新增包可能和已有包冲突,或你想让 Composer 重新协调所有版本 → 用
composer update(它会忽略lock,重新跑 solver,再写新lock) - 更安全的做法是:手动改完
composer.json后,运行composer update --dry-run先看会动哪些包,再决定是否真执行
注意:composer install 在没有 composer.lock 时会自动 fallback 到 update 行为 —— 这也是为什么首次克隆项目后要先 install 而不是 require。
dev 依赖对生产环境的影响(lock 文件视角)
composer.lock 文件本身**总是包含全部依赖**(require + require-dev),无论你用 --no-dev 还是 --production 安装。区别只在 install 阶段是否跳过安装 require-dev 下的包。
-
composer install --no-dev:读取lock中所有包信息,但只安装require列表里的包(require-dev的包不下载、不解压、不写入vendor/autoload.php) -
composer.lock里仍保留 dev 包的哈希、版本、source URL 等元数据 —— 这是为了保证install --no-dev和install基于同一份确定性快照 - 所以,即使你在生产环境用
--no-dev,只要composer.lock里有 dev 包记录,CI 就能复现完全一致的依赖解析过程
为什么有时 require --dev 会升级非 dev 包?
因为 Composer 的依赖求解器不区分“主依赖”和“开发依赖”的优先级 —— 它把整个 composer.json 当作一个约束集来解。例如:
"require": {
"monolog/monolog": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.5"
}
而 phpunit/phpunit ^10.5 可能要求 phpunit/php-code-coverage ^10.1,后者又要求 sebastian/version ^4.0,而这个 sebastian/version 的 4.0 版本与 monolog/monolog ^3.0 兼容,但 3.0 版本锁的是 sebastian/version ^3.0 —— solver 就可能把 monolog 也升到 3.1.0 来满足整体一致性。
这就是为什么不能假设 --dev 操作“只影响 dev 区块”。真正隔离变更的唯一方式是:
- 用
composer require --dev --no-update先写 JSON - 再用
composer update phpunit/phpunit --with-all-dependencies(仅更新该包及其子依赖) - 避免全局
update导致意外漂移
lock 文件的精确性,取决于你控制求解范围的粒度,而不是“dev”这个标签本身。










