composer why-not 是唯一能精准定位依赖阻断点的诊断命令,它不修改文件,仅从目标包反向回溯约束图,输出 requires、conflicts 和 platform 不匹配等真实拦路虎。

composer why-not 不是解决冲突的命令,而是唯一能告诉你“谁在拦路”的诊断入口——它不改任何文件,只输出真实阻断点。
为什么 composer why-not 能精准定位第一个拦路虎
Composer 解析依赖时,会构建一个约束图;why-not 不模拟安装,而是从目标包出发反向回溯,直到找到第一个无法绕过的硬性约束。它不关心你本地有没有装那个包,只看 composer.json 和 composer.lock 里已声明或锁定的所有 require、conflict 和 platform 条件。
- 输出中以
requires开头的行,说明某个已存在包强制要求一个与目标版本不兼容的版本(比如spatie/laravel-backup要求illuminate/support^9.0,而你想装的laravel/framework^10.0需要illuminate/support^10.0) - 以
conflicts开头的行是真正无法协商的死锁,比如某包在自己的composer.json里写了"conflict": {"laravel/framework": ">=11"},Composer 直接放弃求解 - 末尾的
platform requirements不匹配(如php: ^8.1但你运行的是 PHP 7.4)常被忽略,但从 Composer 2 开始,这类检查前置到 autoload 阶段,根本走不到依赖解析
怎么写对 why-not 命令才不会白跑
格式错、参数漏、环境没准备好,why-not 就会静默退出或报“package not found”——这不是命令失效,是前提没满足。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 必须带完整包名和版本约束:
composer why-not 'laravel/framework:^11.0',不能写成laravel/framework 11.0(少冒号)或laravel/framework:^11(太模糊,可能被现有锁文件兼容) - 包名含斜杠或特殊字符时,务必加单引号,避免 shell 解析错误,尤其在 zsh 或 Windows 上
- 如果输出为空,先确认是否已执行过
composer install或composer update --dry-run,否则composer.lock缺失元数据,why-not无图可溯 - 若目标包来自
require-dev(如phpunit/phpunit),默认不参与分析,得加--with-all-dependencies才能穿透进去
输出里哪几行真正关键,怎么看懂缩进逻辑
why-not 的输出是缩进结构,本质是一条「拒绝链」:最后一行是你自己的 composer.json 根声明,往上才是层层卡住它的包。别从上往下读,要倒着看。
- 最底层(缩进最多)那一行,往往藏着半年前手动加的
"foo/bar": "dev-fix-branch",它没发版、没更新,却死死钉住整个依赖树 - 出现
Root package requires,说明是你自己写的某条require直接和目标版本互斥,比如同时写了"monolog/monolog": "^2.8"和"some-tool": "^3.0",而后者要求monolog/monolog^3.5 - 某行末尾带
(locked to 2.8.0),表示该版本已在composer.lock固定;删 lock 文件再跑why-not,结果可能完全不同 - 看到
php: ^8.0或ext-zip报不满足,别急着升级 PHP,先用php -v和php -m | grep zip确认运行时真实环境
为什么有时 why-not 查不到,但安装就是失败
它只回答“约束层面为什么不能装”,不处理网络、权限、镜像同步延迟、私有仓库认证失败等非依赖问题。遇到查不到拦路者但依然失败,优先排查这些:
- 运行
composer show vendor/package,如果连这个都报 “not installed” 或 “no matching packages”,说明包名拼错、已被弃用,或你配置的私有 repo 没包含它 - CI 环境中常见旧版 Composer 缓存,导致 Packagist 元数据未刷新;先
composer self-update --2升级到 2.9.6,再试 - 用了
--no-dev但冲突源在require-dev里,why-not默认不看,得显式加--with-all-dependencies - 某些插件(如
composer-unused)或自定义repositories会干扰解析,临时注释掉再试
真正麻烦的永远不是命令敲不对,而是冲突藏在 require-dev 里、某个 replace 规则暗中接管了扩展、或者你本地 config.platform.php 锁死了 PHP 版本,而服务器实际运行环境早已升级。










