直接结论:不要删 vendor 或 composer.lock,先用 composer why-not 定位阻断链,再用 composer require --no-update 精准干预版本约束,最后只更新目标包;因 composer update 卡在“resolving dependencies”是 sat 求解器暴力穷举无交集的语义化版本约束(如 ^1.25 与 ^2.10),非网络问题,需通过 --dry-run -v 确认尝试回退日志,且 require-dev 全程参与解析,composer why-not 是唯一可靠起点。

直接结论:不要删 vendor 或 composer.lock,先用 composer why-not 定位阻断链,再用 composer require --no-update 精准干预版本约束,最后只更新目标包。
为什么 composer update 会卡在 “Resolving dependencies”
这不是网络慢,是 Composer 的 SAT 求解器在暴力尝试所有可能的版本组合,而你的约束之间没有交集。比如一个包要求 monolog/monolog:^1.25,另一个要求 monolog/monolog:^2.10,语义化版本无重叠,它就永远找不到解。
- 运行
composer update --dry-run -v,看日志里反复出现Trying+ 回退,确认是解析瓶颈 - 别信“等一会儿就好”,超过 3 分钟基本就是约束冲突,不是临时卡顿
-
require-dev里的包(如phpunit/phpunit)全程参与解析,哪怕你只跑composer install
composer why-not 是唯一靠谱的起点
它告诉你谁在联合封杀某个版本,比报错信息直观得多。例如报错说不装 laravel/framework:v10.32.0,你就跑:
composer why-not laravel/framework:10.32.0
输出会列出从顶到底的阻断链,比如:
-
package-x v2.1.0requiressymfony/console:^5.4 -
package-y v3.0.0requiressymfony/console:^6.0 - 而
laravel/framework:10.32.0要求symfony/console:^6.2
这时真正卡点是 package-x,不是 Laravel 本身。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
怎么安全地改版本约束而不牵连其他包
盲目改 composer.json 然后全量 update 极易引发连锁冲突。正确做法是分两步:
- 先执行
composer require monolog/monolog:2.9.3 --no-update—— 只写进composer.json,不触发重解析 - 再执行
composer update monolog/monolog—— 让 Composer 仅围绕这个包重新计算依赖子图 - 如果仍失败,说明还有其他包硬绑了互斥版本,此时用
composer show -t | grep monolog看实际被谁拉入
注意:composer update vendor/package 不等于“只更新这个包”,它会以该包为根重建整个子依赖树,可能激活被压制的老约束。
容易被忽略的三个硬性规则
很多人以为 conflict 和 replace 是提示字段,其实它们是强制拦截开关:
-
"conflict": {"laravel/framework": ">=11.0"}会全局生效——哪怕你没requireL11,只要某个已装包间接拉进来,就会直接拒绝安装 -
replace后必须确保替代项能 100% 覆盖原功能,否则运行时报错,比如用mockery/mockery替换phpunit/phpunit的 mock 机制?不行,PHPUnit 内部调用路径绕不开自己 -
minimum-stability默认不降级,写dev-main却没配"prefer-stable": true,Composer 就直接忽略该版本,不是找不到,是主动跳过
复杂项目里,conflict 字段常被误用来“提醒用户注意版本”,这只会让问题更隐蔽——它该用于强互斥场景,比如两个包提供同一组 API 且无法共存。










