composer why-not是唯一能精准定位依赖阻断点的只读诊断命令,它从目标包反向回溯composer.json和composer.lock中的require、conflict及platform约束,输出首个不可绕过的硬性冲突源。

composer why-not 是定位死锁的第一反应命令
遇到 root requirements could not be resolved 报错时,别删 composer.lock 或盲目改约束——composer why-not 是唯一能立刻指出“谁在拦路”的只读诊断工具。它不模拟安装、不修改文件,只从目标包反向遍历当前 composer.json 和 composer.lock 中所有 require、conflict 和 platform 约束,找到第一个无法绕过的硬冲突点。
常见错误现象:
- 运行
composer why-not laravel/framework:11.0却报[InvalidArgumentException] Package not found:八成是没写精确版本号,正确写法是composer why-not laravel/framework:11.0.0 - 输出为空:说明目标包未被任何现有依赖引用,问题不在依赖图里,要检查拼写、PHP 版本、
minimum-stability或私有仓库可达性 - 输出中出现
conflicts行:这是真死锁,比如某包写了"conflict": {"laravel/framework": ">=11"},Composer 直接放弃求解
用 composer prohibits 主动探雷,尤其适合升级前扫描
composer prohibits 不等你“想装什么”,而是主动扫描整个依赖图,列出所有明确声明排斥目标版本的包。它比 why-not 更早暴露阻断源头,适合在升 Laravel、Symfony 等主框架前做预防性检查。
实操建议:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 准备升
laravel/framework到 v11,先跑composer prohibits "laravel/framework:11.0.0",提前看到spatie/laravel-backup或orchestra/testbench是否还在锁死旧版 - 输出中带
(by your requirements)的行,是你自己的composer.json在作祟,不是第三方包的问题 - 若多个包都禁止同一版本,优先处理
require-dev里的工具链包——它们常因测试兼容性滞后于主框架
用 --dry-run -v 捕捉 SAT 求解器的真实卡点
当 composer update 卡在 Resolving dependencies 超过 3 分钟,不是网络慢,是 SAT 求解器在暴力试错。加 --dry-run -v 能让日志吐出真实瓶颈,这不是日志,是求解器的决策痕迹。
重点盯最后 5–10 行:
- 反复出现
Trying monolog/monolog 1.25.0 → failed:说明这个版本被反复验证又否决,大概率是某个包把它钉死了 - 出现
Rejecting vendor/b because it requires vendor/a ^2.0,而锁文件里是vendor/a:1.9:版本约束在闭环里互相拉扯 - 同一组包名(如
myorg/core → myorg/api → myorg/core)嵌套出现 ≥3 次:强循环信号
用 composer show -t --no-dev --ignore-platform-reqs 查真实依赖树
composer show -t 默认包含 require-dev 和跳过平台检查,容易掩盖真实冲突点。死锁往往藏在“生产环境实际会加载的子图”里,必须加这两个参数才能逼近 composer install 的真实解析上下文。
人工扫描技巧:
- 看到
vendor/a/package-a v1.3.0 └── vendor/b/package-b ^2.1和vendor/b/package-b v2.1.0 └── vendor/a/package-a ^1.2并存:就是强循环信号 - 某包在树中出现 3 次以上,且每次引入路径不同:值得怀疑,可能是多跳环(如 A→C→B→A)
- Windows 下 cmd 可能截断长树输出,建议用 PowerShell 或加
| more
why-not 和 prohibits 输出里缩进最深的那一行,往往才是真正的卡点。










