composer update --dry-run 是轻量级依赖健康检查工具,完整模拟解析逻辑但跳过写入操作,可暴露冲突、不兼容及意外升级,需配合参数和测试使用。

Composer 的 dry-run 不会真正安装或修改任何文件,但它能准确模拟出 composer update 或 composer install 会触发的所有包变更 —— 这是判断一次更新是否安全、是否引入破坏性依赖的最轻量级验证手段。
什么时候必须加 --dry-run?
当你准备执行 composer update 但项目处于以下任一状态时,跳过 --dry-run 就等于在没看变更清单的情况下直接提交生产部署:
- 主分支有未合并的 PR 正在等待依赖兼容性确认
-
composer.json里用了模糊版本约束(如"^2.0"、"dev-main"或"*@dev") - 上一次
composer.lock提交距今超过两周,且团队多人协作频繁 - CI 流水线报了
Root package requires ... but it is not installed类错误,需快速定位是否由本地 lock 文件过期导致
composer update --dry-run 看懂这三行关键输出
运行后终端不会显示“成功”,而是列出拟变更的包清单。重点盯住这三类行:
- 以
Updating ...开头的行:表示该包将被升级(含版本号变化),例如Updating monolog/monolog (2.9.1 => 3.0.0)—— 这里3.0.0是重大版本,需查其UPGRADE.md - 以
Downgrading ...开头的行:极少见但危险,通常意味着某间接依赖强制降级,可能引发方法缺失或行为回退 - 以
Installing ...或Removing ...开头的行:说明依赖图结构发生变动,比如某个包被新版本移除了对symfony/console的 require,或新增了ext-redis扩展要求
注意:--dry-run 不会检查扩展是否已启用,也不会运行 post-update-cmd 脚本 —— 它只做依赖解析与版本比对。
和 composer show --outdated 的本质区别在哪?
composer show --outdated 只告诉你“哪些包有新版本”,但完全不反映实际更新路径;而 --dry-run 是完整走完 Composer 的依赖求解器(SAT solver),结果具备真实执行效力:
-
show --outdated可能显示guzzlehttp/guzzle: 7.8.0 => 7.8.1,但--dry-run可能发现因laravel/framework锁定guzzlehttp/psr7版本,最终guzzlehttp/guzzle实际无法升级 - 某些包在
--outdated中不出现,却会在--dry-run中被连带更新(比如你只改了phpunit/phpunit版本,结果触发整个测试工具链重算) -
--dry-run会暴露conflict规则的实际生效情况,例如Package foo conflicts with bar >=2.0在求解时被触发,而--outdated完全无视 conflict 声明
容易被忽略的两个边界场景
--dry-run 很快,但不是万能的。这两个点不手动验证,照样会翻车:
- 它不校验
autoload配置变更:如果新版本包把src/改成lib/,或删掉了 PSR-4 映射,--dry-run不会报错,但后续composer dump-autoload可能失败 - 它不处理平台配置漂移:比如本地
php.ini关了extension=mbstring,而新依赖在require里写了"ext-mbstring": "*"——--dry-run会安静通过,真执行时才抛Your requirements could not be resolved
真正安全的更新节奏是:先 composer update --dry-run 看变更,再人工核对关键包的 CHANGELOG,最后在 CI 或 Docker 环境中跑一次真实 composer install + 单元测试。











