间接依赖冲突需用 composer show --tree 和 composer why-not 定位真实依赖链:前者揭示 vendor 中实际安装的嵌套依赖及版本锁定,后者反向追踪阻止升级的根因包;dev 工具常是隐藏源头,可用 composer prohibits 或 --no-dev 验证。

间接依赖冲突无法靠看 composer.json 发现,必须用 composer show --tree 和 composer why-not 暴露真实依赖链。
用 composer show --tree 看清谁悄悄拉了旧版本
你写的 composer.json 是愿望清单,composer show --tree 才是 vendor 里实际装了什么。它会一层层展开,暴露出你根本没直接 require、但被某个包偷偷带进来的依赖。
- 执行
composer show --tree | grep "guzzlehttp/guzzle",快速定位 guzzle 在哪一级被引入、锁在哪个版本 - 看到
(locked to 7.4.5)或(replaced)字样,说明这个版本不是你写的,而是某条间接路径强制锁定的 - 如果输出里出现
monolog/monolog被两个不同路径引入(比如一次来自laravel/framework,一次来自spatie/laravel-backup),就基本坐实了间接冲突
用 composer why-not 追到最上面那个“不许升级”的包
报错说 “don’t install monolog/monolog:2.0.0”,别猜,直接查谁在拦路。这个命令输出是反向的:最后一行是你 composer.json 的根声明,往上每行 required by 就是一个卡点。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 必须写全版本号:
composer why-not monolog/monolog:2.0.0,只写monolog/monolog会返回空 - 如果第一行是
Root package requires monolog/monolog ^1.25,说明是你自己写的约束太窄;如果是spatie/laravel-backup 7.0.0 requires monolog/monolog ^1.25,那问题就在 backup 包身上 - 输出为空?先检查
require-dev—— 很多间接锁死来自phpunit/phpunit或mockery/mockery拉着老版sebastian/exporter,间接卡住symfony/console
用 composer prohibits 快速扫清 dev 工具链干扰
很多看似生产环境的冲突,其实根源在测试工具上。它们对 PHP 版本、扩展或主框架有强约束,却和线上运行时无关。
- 执行
composer prohibits monolog/monolog:^2.0,它会列出所有明确拒绝monolog/monolog2.x 的包,比如phpunit/phpunit 9.5.0 requires monolog/monolog ^1.25 - 验证是否是 dev 工具导致:运行
composer update --no-dev,如果成功,说明冲突源就在require-dev里 - 临时绕过:加
--with-all-dependencies强制重算整条链,但别直接提交,先确认新组合真能跑通
间接依赖冲突最难缠的地方在于:它不报错在你改的那一行,而是在你完全没碰过的第三方包里。每次 composer update 前,先跑一遍 composer show --tree | grep 和 composer why-not,比删 vendor 和 composer.lock 有效十倍。

















