Composer核心是SAT求解器驱动的依赖解析工具:install跳过求解、按lock精确安装,update则启动BacktrackingSolver在版本空间搜索可行解;无解时报错是数学结论而非网络问题。

Composer 安装包时不是简单下载 ZIP 或克隆 Git,而是一整套依赖求解 + 确定性安装流程;composer install 和 composer update 的行为差异本质是「是否触发 SAT 求解」。
install 为什么快、update 为什么卡
composer install 完全跳过依赖求解,只读 composer.lock 里记录的精确版本、哈希、自动加载映射,逐条下载并解压到 vendor/。只要 lock 文件存在且完整,过程就是确定性、可重现、不联网(除非包 dist URL 失效)。
composer update 则启动 BacktrackingSolver,把每个 require、conflict、platform 配置都转成逻辑子句,在版本约束空间里搜索可行解。一旦无解,就报 Your requirements could not be resolved to an installable set of packages——这不是网络问题,是数学上证明无解。
- 执行
composer update foo/bar只重解该包及其直系依赖,相对可控 - 执行
composer update --with-all-dependencies会强制重解整个树,内存占用陡增,CI 中慎用 - 删掉
composer.lock后再composer install,等价于composer update,会悄悄触发求解
包到底怎么装进 vendor 的
安装方式(dist 还是 source)由多层策略叠加决定,preferred-install 只是提示,不是开关:
- 命令行参数优先级最高:
--prefer-dist或--prefer-source直接覆盖配置 - 包自身
composer.json必须提供dist字段(如"dist": {"type": "zip", "url": "..."}),否则即使配了"*": "dist"也会静默 fallback 到source - 私有 GitLab/GitHub 仓库若未开启 archive 功能,
dist就不可用 -
require-dev包默认也走同样路径,只是语义上标记为开发期使用
autoload.php 是怎么生成的
vendor/autoload.php 不是固定文件,而是每次 install 或 update 时由 Composer 自动生成的加载器入口,它聚合了所有包的自动加载规则:
- PSR-4 映射来自各包
composer.json的autoload.ps4字段,合并后写入vendor/composer/autoload_psr4.php - Classmap 来自
autoload.classmap或composer dump-autoload --optimize扫描结果 - 如果某个包声明了
autoload-dev,它的路径只在composer install(非--no-dev)时注入,但不会影响运行时加载逻辑 - 修改
composer.json后没生效?先确认是否执行了dump-autoload,或是否误删了vendor/composer/下的缓存文件
platform 配置为什么有时不生效
config.platform 是在依赖解析阶段起作用的“目标环境声明”,不是运行时检测机制:
- 必须写在
composer.json的config对象下,例如:"config": {"platform": {"php": "8.1.10", "ext-redis": "5.3.7"}} - 它只过滤那些**显式声明了依赖扩展**的包(比如某包
require了"ext-pcntl": "*"),对没声明的包完全无效 - PHP 版本模拟最可靠;扩展模拟效果取决于生态规范程度——2026 年主流包基本补全了
ext-xxx声明,但小众封装器仍可能漏掉 - 设了
platform却还是装了高版本包?检查该包的composer.json是否根本没写require扩展,那 platform 就形同虚设
真正容易被忽略的是:lock 文件不是缓存,是求解器输出的可验证数学解;vendor 目录不是源码仓库,只是该解的可重建产物。任何绕过 lock 的操作(比如手动改 composer.json 后直接 install),都在暗中触发一次全新求解——而你未必意识到这点。


















