composer why --tree 可追至项目根目录,显示完整依赖路径;若中断则可能被 replace/provide 隐藏,需结合 composer show --tree 验证;加 --dev 查开发依赖,空结果需确认包名、锁文件存在性及是否为根依赖。

composer why 只显示第一层依赖,怎么追到最源头?
它默认只告诉你「谁直接 require 了这个包」,比如 composer why monolog/monolog 输出 laravel/framework v10.48.12 requires monolog/monolog (^2.0),但这只是起点。真正卡升级的,往往是 laravel/framework 自己被谁拉进来的——你得手动再查一次。
实操建议:
- 加
--tree看路径:composer why --tree monolog/monolog可能输出my-project └── laravel/framework ^10.0 └── monolog/monolog ^2.0,说明是你项目根直接或间接引入的 - 如果路径在某一层断掉(比如停在
psr/log就没了),大概率是被replace或provide隐藏了,得结合composer show --tree psr/log对比验证 - 想确认是否被
require-dev拖入?加--dev参数重试:composer why --dev phpunit/phpunit
为什么 composer why 返回空,但 vendor 里明明有那个包?
不是包没装,而是它没走标准 require 链——常见于 dev 包、私有源、或被其他包用 replace 声明替代后又 fallback 安装的残留。
先检查三件事:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 包名拼写必须完全一致:
guzzlehttp/guzzle≠GuzzleHttp/Guzzle,不能漏斜杠 - 运行
composer show确认该包是否真在composer.lock里登记过;若没登记,why就查不到 - 它是不是仅通过
require-dev装的?默认不查 dev 包,得显式加--dev
冲突真正卡在哪儿?别信 why,用 why-not 倒着读拒绝链
composer why 回答“谁把我装进来”,composer why-not 才回答“谁不让我升上去”。报错说不能装 laravel/framework:^11.0,就该立刻跑:composer why-not laravel/framework:11.0.0。
输出是缩进结构,**必须从最后一行倒着看**:
- 最底下那行(缩进最多)才是你的
composer.json根声明,比如Root package requires laravel/framework ^11.0 - 往上每一行,都是一个阻断点:可能是某个已装包的
requires,也可能是它的conflict字段,甚至是 PHP 版本不匹配 - 看到某行末尾写着
(for spatie/laravel-backup v7.2.0),别跳过——这就是你要动手改或删的包
show --tree 比报错更真实,但它暴露的是“已安装现状”,不是“理想解”
composer show --tree 不模拟求解,只摊开当前 composer.lock 里实际存在的依赖树。它能帮你发现那些你以为没装、其实早被 dev 工具拖进来的冲突源。
重点关注:
- 同名包是否出现在多条路径下、且锁定不同版本(如
symfony/console同时被laravel/framework和phpunit/phpunit引入) - 冲突包是否来自
require-dev—— 默认参与解析,哪怕你部署时用了--no-dev - 某行末尾带
(locked to 5.4.3),说明这个版本已被锁死;想松动,得删composer.lock再update,不能只改composer.json
why 默认只返回第一个匹配项;真正要扫清所有引用路径,得配合 composer depends --tree(Composer 2.5+)交叉验证,但注意语义相反——它是查「谁可能用到我」,不是「谁把我拉进来」。










