间接依赖不受项目 minimum-stability 约束,应通过 composer show --tree、composer why 和 composer depends -r 定位真实版本冲突源,而非降级 minimum-stability。

间接依赖不听你项目的 minimum-stability
你设了 "minimum-stability": "stable",不代表 monolog/monolog 拉进来的 psr/log 就得守这个规矩。Composer 对间接依赖(即 A 包 require 的 B 包)完全不应用你项目的 minimum-stability,只认那个包自己 composer.json 里写的约束和它发布的版本标签。
常见错误现象:
- 执行
composer install报错 “Could not find package psr/log with stability dev” —— 但你根本没在require里写它 - 降级项目
minimum-stability到dev后问题消失,但这不是解法,只是掩盖了真正源头
真正该查的是:那个间接依赖包自己怎么选版本。比如运行 composer show monolog/monolog 1.25.0 --tree,看它声明的 psr/log 约束到底是什么,带不带 -dev 后缀。
composer show --tree 是看间接依赖链的唯一可靠入口
它不靠猜测,直接读 composer.lock 或已安装包元数据,把每一层依赖关系按缩进展开。缩进越深,层级越低,越接近间接依赖。
使用场景和要点:
- 必须在项目根目录运行,否则输出为空或报错
-
--no-dev要加:避免开发依赖干扰主线,尤其当冲突来自phpunit拉的旧组件时 - 加具体包名精准聚焦:
composer show --tree --no-dev guzzlehttp/guzzle,比全量树好读十倍 - 看到同一包在不同缩进出现?说明多路径引入,版本可能被锁死——这是冲突高发区
注意:composer show --tree 不会自动标红冲突,但它能让你看清“为什么明明写了 ^3.0,最后却装了 2.9.9”。顺着缩进往上翻两层,大概率发现某个上游包硬写了 "vendor/package": "2.*"。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
composer why 和 composer depends -r 配合定位强制约束源
composer why vendor/package 告诉你“谁把它拉进来的”,而 composer depends -r vendor/package 告诉你“谁在死死卡住它的版本”。两者互补,缺一不可。
关键差异:
-
composer why输出引用链,带版本约束,适合顺藤摸瓜;加-t可展开完整路径:composer why -t symfony/http-kernel -
composer depends -r(-r表示递归)才真正列出所有 transitive dependencies 中对它的约束;不加-r只显示直接 require 的包 - 输出中带
requires的行才是有效约束来源;replaces或provides的不用管
容易踩的坑:用 composer depends 却忘了加 -r,结果只看到顶层依赖,漏掉真正锁版本的第二层包。
间接依赖出问题,90% 不该动 minimum-stability
改项目级 minimum-stability 是最省事的错觉。它相当于给整棵树开绿灯,可能让本不该进生产的 dev 版本混进来,而且治标不治本——下次换个包,问题照旧。
更务实的解法是“假装存在一个稳定版本”,绕过坏引用:
- 用
composer prohibits vendor/package:version查谁在阻止某个版本被选中 - 临时加
"replace": {"psr/log": "*"}到composer.json,骗 Composer 这个包已满足,再配合composer update --with-dependencies局部重解 - 删
composer.lock后composer install,让求解器从零开始找新解(前提是没被旧 lock 文件隐性锁死)
真正复杂的地方在于:间接依赖的约束来自外部包,你无法直接修改。所以分析必须下沉到那层包自己的 composer.json 和发布历史,而不是只盯着自己项目的配置打转。

















