
Composer卡在“Resolving dependencies”不是网络慢,是本地CPU正在暴力穷举所有版本组合——它卡在逻辑冲突里,而不是连不上。
怎么一眼确认是不是SAT求解器卡死
运行composer update -vvv --profile,盯着最后一行输出:
- 如果停在
Resolving dependencies through SAT,就是SAT求解器陷入回溯,和网络、镜像、缓存全无关 - 如果停在
Reading /packages.json from cache或Downloading https://...,才是元数据或包下载问题 - 如果CPU持续飙高、内存缓慢上涨、终端长时间无新日志,基本可断定是约束爆炸
为什么composer why-not比翻composer.json快十倍
composer why-not不查“能不能装”,而是直接展开“谁在阻止共存”,把嵌套多层的约束链一次性打平:
- 例如想装
monolog/monolog:3.0.0失败,执行composer why-not monolog/monolog:3.0.0 - 输出里每行都是一个阻断点:
laravel/framework的require、你项目根conflict、甚至your-project自身写的硬冲突 - 注意
require-dev全程参与解析——phpunit/phpunit要求PHP 8.2,但项目写"php": ">=7.4",也会卡死
--with-all-dependencies和replace怎么用才不翻车
当项目有30+包、含私有仓库或dev-main时,SAT求解可能超10分钟。与其等它穷举,不如主动收口:
-
composer update --with-all-dependencies:跳过子依赖兼容性校验,适合CI快速生成composer.lock,但上线前必须用composer update全量验证 -
"replace": {"psr/log": "3.0.0"}:告诉Composer“这个包我已有实现,别再找兼容版本”,避免它为满足PSR接口反复尝试不同日志库 -
"conflict": {"symfony/console": "=10.0"}:封杀已知死路,防止求解器浪费时间在不可行组合上 - 慎用
--no-plugins --no-scripts:插件可能引入隐式约束,关掉后有时能绕过卡点,但上线前必须开回来验证
容易被忽略但致命的三个配置点
很多优化方案失效,是因为这几个点没对齐:
-
repos.packagist拼错成repo.packagist(少个s),导致镜像配置被完全忽略 -
classmap-authoritative默认开启(Composer 3.x),每次update都强制重扫整个vendor/目录,I/O开销远超网络延迟 -
"php": ">=7.4"这种松散声明会让求解器查几百个包的兼容性元数据,收紧到"php": "^8.1"能立竿见影


















