require-dev依赖冲突是主因,非网络或权限问题;应运行composer why-not定位阻塞链、composer show --tree查真实依赖树,并在composer.json中写死版本后加--with-dependencies更新。

require-dev 依赖冲突是主因,不是网络或权限问题
Composer 安装测试依赖(如 phpunit/phpunit、mockery/mockery、sebastian/exporter)失败,90% 以上不是因为连不上 Packagist,而是 require-dev 区块里藏着的版本锁链在封杀你想要的包。它不显式写在根依赖里,却会强制降级核心组件(比如把 symfony/console 锁死在 5.4.x,导致 Laravel 11 无法装入)。
常见现象包括:
Your requirements could not be resolved to an installable set of packages.- 报错里出现
don’t install vendor/package:version,但你根本没在require里写它 -
composer install成功,composer update却失败——因为require-dev在 update 阶段才参与求解
用 composer why-not 定位真实阻塞点
看到 don’t install phpunit/phpunit:^10.0 这类提示,立刻执行:
composer why-not phpunit/phpunit:^10.0
输出是倒序链路,从最后一行(Root package)往上读,每行末尾的 (required by xxx) 就是上一级约束来源。重点看中间带 require-dev 的那一行——它往往来自你项目里某个测试工具的子依赖,而不是你主动写的。
如果输出为空,大概率是以下两种情况之一:
- 版本号写错,比如
phpunit/phpunit:9.99(实际最高只到 9.6.x) - 冲突来自
require-dev中某包的隐式依赖,例如phpunit/phpunit拉了sebastian/exporter:^5.0,而另一个 dev 工具又要求^4.0
composer show --tree 是唯一可信的依赖快照
composer.json 是愿望清单,composer.lock 和 vendor/ 才是现实。运行:
composer show --tree | grep "phpunit"
能直接看到 phpunit/phpunit 被谁引入、锁在哪个版本、是否标着 (locked to 9.5.27)。再查它和关键包的关系:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
composer show --tree phpunit/phpunit | grep -A3 -B3 "symfony/console"
如果发现某条路径上 symfony/console 被锁死在 5.x,而你要升级 Laravel,就得顺着那条路径去查是谁在提这个要求——很可能是 orchestra/testbench 或 laravel/pint 的旧版。
注意:(replaced) 或 (provided) 标记不能轻信,得去那个包自己的 composer.json 里确认 replace 字段是否真能等价替代。
更新测试依赖必须加 --with-dependencies,且先改 composer.json
直接跑 composer update phpunit/phpunit 几乎必踩坑:它默认不更新子依赖,结果 phpunit 升了,sebastian/exporter 还卡在老版,运行时直接报错。
正确做法分三步:
- 先在
composer.json的require-dev里写死目标版本,例如"phpunit/phpunit": "^10.5" - 再执行
composer update phpunit/phpunit --with-dependencies - 加
--dry-run预览:composer update phpunit/phpunit --with-dependencies --dry-run,确认只有预期包及其直系依赖变更
执行后立刻 git diff composer.lock:如果改动范围超出预期(比如连 guzzlehttp/guzzle 也被动升了),说明约束没控住,得回退并检查有没有其他 dev 包在悄悄拉低版本。
真正难处理的,是多个 require-dev 工具对同一底层包(如 symfony/yaml、psr/log)提出互斥版本要求。这种时候,要么降级某个 dev 工具,要么用 config.platform 锁定 PHP 版本避免自动选高版本依赖,别指望靠删 vendor 和重跑 install 解决。










