Composer解析慢主因是SAT求解器单核暴力回溯,与镜像、并发无关;需提交composer.lock、清理require-dev、统一minimum-stability策略并配置正确镜像源。

多模块项目里 Composer 解析慢,90% 不是网络或磁盘问题,而是 SAT 求解器在单核上暴力回溯——它得从几百个包、上千条约束里找出唯一可行解。你改镜像、加并发,只要 composer.lock 没提交、require-dev 没清理、求解逻辑没绕过,就还在原地打转。
为什么 composer install 卡在 “Resolving dependencies…” 几十秒
这不是下载卡住,是 PHP 在跑 SAT(布尔可满足性)求解器,位置在 src/Composer/DependencyResolver/Solver.php。它把每个包的版本约束转成逻辑命题,再穷举组合验证是否自洽。模块越多、私有包约束越细(比如 "myorg/*": "^2.1")、composer.lock 越大(超 8MB),CPU 就越容易满载单核。
常见现象:
- 本地
composer install有时快有时慢,但 CI 流水线每次稳定卡 40+ 秒 - 删掉一个
require-dev包,解析时间直接降 30% - 执行
composer update --dry-run也卡,证明纯属求解阶段耗时
必须提交 composer.lock,且定期瘦身
composer.lock 不只是“锁版本”,它存了每个包的完整元数据:dist checksum、source commit、require-dev 列表、甚至被 archive.exclude 排除路径的 hash。多模块项目里,重复字段和残留 dev 包会让它膨胀到十几 MB,解析开销指数级增长。
实操建议:
- 永远
git add composer.lock—— 不提交 = 每次install都重跑 SAT - 运行
composer update --lock(不带包名),它会压缩 JSON、合并冗余字段、剔除已不存在的包记录 - 所有私有模块的
composer.json加上"archive": {"exclude": ["/tests", "/docs", "/examples"]},否则 lock 文件仍记这些路径的 hash - 用
composer why-not some/package查清某个包为何被拉进来,再决定是否从根composer.json中移除
删 require-dev 比换镜像更管用
很多人以为 --no-dev 能跳过 dev 依赖的解析——错。它只跳过安装,不跳过解析。所有 require-dev 的包仍参与 SAT 求解,哪怕最终不落地 vendor/。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
典型浪费点:
-
phpunit/phpunit旧版本(如 8.x)还留在require-dev,但项目已升到 PHP 8.2+ -
phpstan/phpstan和psalm/phar同时存在,互相推高版本下限 - 本地调试用的
symfony/var-dumper被写进项目级require-dev,而非全局安装
正确做法:
- 把通用工具(
phpunit、phpcs、phpstan)移到全局:composer global require phpunit/phpunit - CI 环境中统一用
composer exec phpunit,不依赖项目级 vendor/bin - 检查
composer.lock里packages-dev数量,超过 50 个就要动手砍
别碰 hirak/prestissimo,也别信“二进制加速”
Composer 2.x 从 2.0 开始已原生支持并行 HTTP 下载(基于 cURL multi),composer install 默认就启用。装 hirak/prestissimo 这类第三方插件,不仅无效,还会和内置并发机制冲突,导致 Segmentation fault 或内存溢出——尤其在多模块项目频繁 update 时。
真正该调的并发参数只有这个:
-
composer config -g parallel-downloads 8—— Composer 2.2+ 支持,设为 8 是实测平衡点;设 10 容易触发临时文件竞争,报file_put_contents(/tmp/): failed to open - 镜像源必须配对生效:
composer config -g repo.packagist composer https://mirrors.huaweicloud.com/repository/php/composer/(注意末尾/和 key 名是repo.packagist,不是repos.packagist) - 项目级
repositories会覆盖全局镜像,空对象"repositories": {}也生效 —— 宁可删掉,也不要留空
最常被忽略的点:多模块项目往往共用一套私有 Packagist,但每个模块的 composer.json 里都写了 "minimum-stability": "dev" 或宽松的 "prefer-stable": false,这会让 SAT 求解器候选版本数翻几倍。统一收口到稳定策略,比调任何参数都管用。

















