composer install 没有 composer.lock 时会隐式执行不受控的 composer update,从头解析 composer.json 的版本约束,安装未经验证的最新兼容版本,导致环境不一致、兼容性风险及安全校验失效。

必须提交 composer.lock,否则 composer install 就不是“还原环境”,而是隐式执行一次不受控的 composer update —— 你根本不知道它会装什么。
composer install 没有 lock 文件时到底做了什么?
它会忽略 composer.json 里所有波浪号(^)、兼容号(~)或范围写法,从头解析整个依赖树,取每个包当前满足约束的最新版本。这个结果:
- 没人验证过是否兼容你的代码(比如
monolog/monolog从2.10.2升到2.11.0,可能悄悄改了LoggerInterface的方法签名) - 不保证 PHP 版本兼容(
lock里明确写了"platform": {"php": "8.1.0"},没它就可能装上要求php >=8.2的子依赖) - 哈希校验失效,无法防篡改(
lock中每个包都有"content-hash"和"dist": {"sha256": "..."})
为什么团队成员执行 composer install 后 vendor 不一致?
常见原因就是有人删了 composer.lock、或 Git 忽略了它、或 CI 流水线里用了 --no-lock。后果直接体现在:
-
Class not found:某个包的类在新版本里被移入新命名空间 -
ArgumentCountError:函数参数数量或类型变了,但类型声明没报错(PHP 8.0+ 之前) - CI 构建通过,生产环境失败:因为 CI 用的是旧缓存或旧镜像,而你本地跑的是全新解析结果
哪些项目该提交 composer.lock?
只看一个标准:这个项目最终是否会被部署运行。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 应用型项目(Laravel/Symfony 站点、API 服务、CLI 工具)→ 必须提交
composer.lock - 库项目(你写的
myorg/utils,供别人require)→ 绝不提交composer.lock,否则会锁死下游用户的依赖选择
Git 提交记录里如果出现 composer.lock 被重写或重建,基本意味着某次发布已脱离受控状态。
CI/CD 中误用 composer update 的真实代价
很多团队把 composer update 放进构建脚本,以为“自动更新最安全”。实际是:
- 每次构建都可能拉到不同版本,等于放弃可重现构建
- 安全扫描(如
composer audit或 SCA 工具)无法比对历史基线,告警失真 - 哪怕只更新一个包(
composer update monolog/monolog),也会连带升级其子依赖,而这些子依赖未必经过测试
真正该做的,是在开发机上运行 composer update → 提交新的 composer.lock → CI 执行 composer install。顺序不能颠倒,也不能跳过 lock 文件校验。

















