Composer install卡在“Resolving dependencies”是SAT求解器因依赖递归爆炸而穷举版本组合,导致CPU/内存飙升、长时间无响应;应通过--no-dev、why-not、prohibits、platform校准及replace收敛求解空间。

Composer install 卡在 “Resolving dependencies” 不是网络慢,也不是镜像没换对,而是 SAT 求解器正在穷举版本组合——一旦约束过紧或嵌套太深,CPU 会拉满、内存暴涨、10 分钟没日志输出,这是典型的依赖递归爆炸。
为什么composer install卡在“Resolving dependencies”
这不是下载卡住,是 PHP 进程在本地做逻辑推理:它要找出一组满足所有 require、conflict、replace、PHP platform、甚至私有包 minimum-stability 的版本组合。当项目含 Laravel + 20+ 私有包 + 多层 conflict 规则时,求解空间可能达百万级,PHP 解析 JSON + 构建图 + 回溯尝试,直接把机器拖死。
- 典型现象:
top看到php进程 CPU 占用 99%,内存持续上涨,终端无新日志 - 不是
composer.lock文件损坏,而是它记录了一个“脆弱解”,当前环境(如 PHP 版本微调)已无法复现 -
--no-cache或删vendor/无效——问题不在缓存,而在求解逻辑本身
快速定位阻断点:用why-not和prohibits反向查
别猜哪个包冲突,让 Composer 自己指出来。假设你想装 laravel/framework:10.32.0 却卡住,就运行:
composer why-not laravel/framework:10.32.0
输出里每一行都是一个真实拦路虎,比如:
-
spatie/laravel-backup v7.5.0 requires laravel/framework ^8.0|^9.0→ 它硬性拒绝 L10 -
your-project requires guzzlehttp/guzzle ^7.0→ 而 L10 默认 require Guzzle 8+ -
monolog/monolog v1.27.1 conflicts with guzzlehttp/guzzle ^7.0→ 冲突链已闭环
再补一句:
composer prohibits monolog/monolog:^2.0
看谁在锁死 Monolog 2.x——常是某个旧版测试工具(如 phpunit/phpunit:9.5)的 require 里写了 "monolog/monolog": "^1.25"。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
收敛求解空间:删 dev、压 platform、用 replace
大型项目里,require-dev 是隐形炸弹:它们不参与运行,但强制进入求解图。先验证是否 dev 拖累:
composer update --no-dev -v
如果成功,说明冲突源在 dev 工具链里(比如 phpstan/phpstan 和 larastan/larastan 对 PHP 版本要求不一致)。接着检查 composer.lock 顶部的 platform 字段是否与当前环境匹配;若不匹配,别用 --ignore-platform-reqs 硬上,而是显式对齐:
- 在
composer.json中加:"config": {"platform": {"php": "8.1.10", "ext-pdo": "8.1.10"}} - 再跑
composer update --lock,让 lock 文件固化这个平台声明 - 真没法升级底层包?比如必须用 PHP 7.4,但
guzzlehttp/guzzle最新版要 PHP 8.0+,就用replace告诉 Composer:“我已有替代”:"replace": {"guzzlehttp/guzzle": "7.7.*"}注意:这不解决运行时兼容,只跳过求解——你得自己确保guzzlehttp/guzzle:7.7真能跑通全链路
composer.lock过大也会拖慢解析
一个 12MB 的 composer.lock 不是“信息多”,而是冗余元数据堆出来的。Composer 解析它要加载整个 JSON 到内存,再逐字段校验。常见膨胀原因:
- 私有包没配
"archive": {"exclude": ["/tests", "/docs"]},导致每个被排除路径都记了 hash -
require-dev里残留已废弃的调试包(如barryvdh/laravel-debugbar:3.6),它们虽不安装,但仍在 lock 中占解析开销 - 长期未执行
composer update --lock,字段未压缩、JSON 未格式化
实操建议:
- 删掉确定不用的
require-dev条目,再跑composer update --lock - 对所有私有包补上
archive.exclude配置 - 用
composer show --tree | wc -l粗略估算依赖深度,超 15 层就要警惕递归风险
真正卡住时,最省时间的做法不是重试或删锁文件,而是打开 -v 日志,盯住最后 5 行反复出现的包名——那大概率就是递归回溯的锚点,从它开始查 why-not,比盲目清理快得多。

















