composer.lock是强制契约而非可选文件,它使composer install严格按锁定的精确版本、URL、commit hash和校验和安装,忽略composer.json中所有版本约束,确保环境一致、安装高效、构建可重现。

composer.lock 文件不是可选附件,而是团队协作的强制契约——没它,composer install 就会退化成不可控的 composer update,环境不一致问题必然爆发。
为什么 composer install 必须依赖 composer.lock
它不是“参考”,是唯一安装依据:composer install 完全忽略 composer.json 里的 ^7.0 或 ~2.5 这类范围约束,只认 composer.lock 中记录的精确版本号、dist URL、commit hash 和校验和。
- 常见错误现象:
Class 'Symfony\Component\HttpClient\HttpClient' not found—— 本地能跑,CI 失败,大概率是composer.lock没提交或被误删 - 同事装出
guzzlehttp/guzzle7.8.1,你装出 7.9.0,但两人都没改composer.json?说明 lock 文件缺失,install实际执行了隐式更新 - 性能影响:跳过依赖解析过程,安装速度显著快于
update;无 lock 时首次install会变慢且结果不可复现
Git 合并冲突时绝不能手动编辑 composer.lock
它不是普通配置文件,而是整个依赖图的完整序列化快照。手动删行、保留“这边的”包、“那边的”哈希,99% 会导致子依赖断裂或安装失败。
- 正确做法:任选一端还原 lock 文件(
git checkout --ours composer.lock或git checkout --theirs composer.lock) - 删掉
vendor/目录,确保干净 - 运行
composer install—— 它会基于当前composer.json和刚恢复的 lock 校验并生成新 lock - 如果提示
Your lock file does not contain a compatible set of packages,说明composer.json已被他人修改,先git pull,再composer install
composer update 是主动升级动作,不是日常命令
它会重算整个依赖树,可能引入未经测试的小版本、BC break,甚至因平台限制降级到带已知 bug 的旧版。它的使用必须有明确目标和上下文。
- 适用场景仅限于:
laravel/framework主版本升级、修复高危 CVE(如monolog/monologCVE-2025-1234)、适配新 PHP 版本(如 PHP 8.4) - 升级单个包时务必加
--with-all-dependencies,否则主包升级了,子依赖卡在旧版,行为仍不可控 - CI/CD 脚本里禁止出现
composer update,除非是专门做依赖审计的独立任务 - 每次
composer update后,必须git add composer.lock并提交,否则升级等于白干
真正容易被忽略的点在于:lock 文件的效力依赖于基础环境的一致性。比如 "platform": {"php": "8.1.0"} 配置下,不同机器 PHP 版本不一致时,composer install 可能静默选择兼容版本——这不是 lock 失效,而是平台约束生效。统一运行环境,才是 lock 发挥作用的前提。











