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

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开头的行是真死锁,比如某包写了"conflict": {"laravel/framework": ">=11"},Composer 直接放弃求解 - 末尾出现
platform requirements不匹配(如php: ^8.1但你运行的是 PHP 7.4),这类问题从 Composer 2 开始前置到 autoload 阶段,根本不会走到依赖解析环节
运行 composer why-not 时必须注意的三个细节
它对输入格式和环境非常敏感,错一个就查不到真实原因:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 必须用**精确版本号**,不能写
^3.0或3.0.*;报错[InvalidArgumentException] Package not found八成是这个原因。正确写法是composer why-not laravel/sanctum:3.0.0 - 确保 Composer 版本 ≥ 2.2;低于该版本会提示
Command "why-not" is not defined,需先运行composer self-update --2 - 若目标包被
require-dev中的包间接依赖,需加--with-all-dependencies才能穿透检查,否则可能漏掉关键阻断点
为什么有时 composer why-not 输出为空
这不代表没冲突,而是说明:目标包未被任何现有依赖引用,问题不在依赖图里。
- 检查是否拼错了包名或版本号(比如把
monolog/monolog写成monolog/monologg) - 确认 PHP 版本、扩展(如
ext-curl)、minimum-stability设置是否满足目标包要求——这些不会出现在why-not输出中,但会导致安装失败 - 如果项目用了私有仓库或自定义
repositories,why-not不校验网络可达性或认证状态,它只看约束逻辑
当 composer why-not 查不到时,用 prohibits 替代
composer prohibits 更适合“我想装但装不上”的场景,尤其当你没在 composer.json 里显式 require 过目标包时:
-
composer why-not laravel/framework:11.0.0可能返回空(因为你没写过它),但composer prohibits laravel/framework:11.0.0会立刻指出spatie/laravel-backup v7.2.0 requires symfony/console ^5.4 - 它不区分
require和require-dev,默认全量扫描,更接近“真凶画像” - 同样要求精确版本号,且只对 Packagist 上已发布的版本有效
真正卡住人的往往不是命令本身,而是把 why-not 当成万能钥匙——它只管依赖逻辑冲突,不管网络超时、私有源认证失败、PHP 扩展缺失或 composer.lock 文件损坏。先确认这些基础条件成立,再让它干活。










