composer why-not是定位依赖冲突链的唯一可靠起点,它通过反向追溯输出完整阻断路径,如显示myapp/myproject和symfony/http-client对guzzlehttp/guzzle提出互斥版本要求,而非仅报“don’t install”。

composer why-not 是定位冲突链的唯一可靠起点
报错里写的 “don’t install xxx” 只是结论,真正要查的是谁在联合封杀——composer why-not vendor/package:version 才能列出完整阻断路径。比如 composer why-not guzzlehttp/guzzle:^7.5 会输出类似:
myapp/myproject dev-main requires guzzlehttp/guzzle ^6.5 symfony/http-client v5.4.0 requires guzzlehttp/guzzle ^7.0.1
这说明根项目和 Symfony 的子依赖对 Guzzle 提出了互斥要求。此时不能只盯着 Guzzle,而要看 symfony/http-client 是否可降级,或 myapp/myproject 的 Guzzle 约束是否能放宽。
- 如果
why-not输出为空,说明该版本根本不在 Packagist 上存在,不是冲突,是版本写错了 - 若第一行显示的是
require-dev工具(如phpunit/phpunit)在拉旧版,得检查是否误把开发依赖当生产依赖用了 - 注意
conflict字段:某个包声明了"conflict": {"guzzlehttp/guzzle": ">=7.0"},哪怕你没直接 require 它,只要它被其他包间接引入,就会触发阻断
用 --with-dependencies 定点升级,别碰无关分支
盲目 composer update 会让 SAT 求解器重算整个依赖树,容易卡住或带偏稳定子依赖。真要升一个包,必须显式指定且加 --with-dependencies:
composer update monolog/monolog --with-dependencies
这个命令只允许 Composer 升级 monolog/monolog 及其**直接依赖**,不会动 phpunit、symfony/polyfill 这类无关项。不加这个参数,Composer 往往直接拒绝执行,报 “无法满足要求”。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 写法必须是
vendor/package,不能带引号、不能带^或~,例如composer update "monolog/monolog:^3"是错的 - 升级后立刻
git diff composer.lock,确认只有预期包及其直系依赖变更;多改一个symfony/polyfill-mbstring都可能引发运行时 autoload 失败 - 如果失败,说明该包的子依赖链里还有硬冲突,此时再跑一次
composer why-not查新暴露出来的包
放宽约束前先确认兼容性,别信“中间版本万能”
看到两个包分别要求 ^1.0 和 ^2.0,别急着改成 ^1.0 || ^2.0。语义化版本的大版本跃迁往往意味着 API 不兼容,强行合并只会让代码在运行时报 Class not found 或 Method not exists。
- 去 Packagist 查目标包的
changelog或UPGRADE.md,确认 v2.x 是否提供向后兼容的 facade 或 polyfill - 如果只是某工具包(如
phpstan/phpstan)要求高版本 Guzzle,而你的业务代码根本不调用 Guzzle,可考虑用replace声明替代:"replace": {"guzzlehttp/guzzle": "*"},但前提是已通过symfony/http-client或其他方式覆盖全部网络请求逻辑 - 更稳妥的做法是找“被共同接受”的版本,比如
v2.9.3同时出现在 A 包的^2.0和 B 包的>=2.8.0范围内——这种交集才是 Composer 能解出的真解
删 composer.lock 不是解决,是放弃线索
composer.lock 是契约,不是缓存。删了它再 composer install,等于让 Composer 在当前时间点重新解析全量依赖图,结果很可能和原环境不一致:
- Packagist 上已有新版本发布(如
monolog/monolog刚发了3.6.0),而你原来锁的是3.5.0 - 某个间接依赖的
require-dev里混进了"phpunit/phpunit": "dev-main",新解析会把它拉进来 - 本地 PHP 版本变了(比如从 8.1 升到 8.3),但
composer.json没配"platform",新解析默认选了不兼容的包
真正该用的是 composer update --lock:它不升级任何包,只刷新 lock 文件结构、补全字段、校验哈希。适用于改了 platform 配置或修复 Git 合并冲突后的 lock 文件脏内容。
复杂点在于:很多冲突不是单层问题,而是 A → B → C → A 这样的闭环,或者 conflict 字段在私有包里被误用。这些情况必须靠 composer depends --tree 和反复 why-not 交叉验证,没有跳过分析的捷径。










