composer install 必须依赖 composer.lock,因为它本质是还原已验证的依赖状态,而非解析 composer.json 的版本约束;缺失 lock 会导致隐式 update、环境不一致及线上故障。

composer install 为什么必须依赖 composer.lock
因为 composer install 的本质不是“安装当前声明”,而是“还原上次验证过的状态”。它完全跳过 composer.json 中的版本约束(比如 "^2.1" 或 "~3.0"),只读取 composer.lock 里记录的精确版本号、哈希值和完整依赖树。没有这个文件,它会退化为隐式 composer update,结果不可控。
常见错误现象:
- CI 构建成功但线上报
Class not found或TypeError—— 实际是 lock 缺失,触发了未测试的子依赖升级 - 团队成员执行
composer install后vendor/内容不一致 —— 某人本地没提交composer.lock,或 .gitignore 里误加了它 -
composer install执行后composer.lock文件内容被修改 —— 说明 lock 和composer.json已不兼容(如删了包但没清理 lock),Composer 在“修复”而非“更新”
部署脚本里漏掉 --locked 就等于放弃一致性
composer install --locked 是生产环境唯一安全的写法。它强制要求 composer.lock 存在且格式合法;一旦失败,立刻中断,绝不 fallback 到重算逻辑。
不加 --locked 的风险:
- CI 流水线缓存了旧 lock 或漏掉
ls -la composer.lock检查步骤 → 装出和本地开发不一致的依赖组合 - Git 提交前没运行
composer update就改了composer.json→ 别人composer install会失败,因为 lock 里没对应版本 - 某些 CI 环境默认启用 --no-interaction,但没配 --locked → 静默降级为 update 行为,埋下发布隐患
require 和 install 不是替代关系,不能靠手动改 JSON + install 加新包
你改完 composer.json,再跑 composer install,它依然只按旧 lock 装——新加的那行声明被彻底忽略。只有两种方式能让新包落地:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 用
composer require vendor/package-name:安全,局部重算,composer.lock自动同步,还带废弃包警告 - 删掉
composer.lock再跑composer install:危险!会重算全部依赖,版本不可控,等价于不受控的composer update
顺带一提:composer require 触发的 warning(如 Package xxx is abandoned)只出现在 install/update 时,require 本身不检查已装包是否废弃——它只管自己新加的这个。
lock 文件没提交 = 版本控制失效
对应用型项目(Laravel 网站、Symfony API),composer.lock 必须提交到 Git,且不能忽略。这不是“可选最佳实践”,而是版本控制链条上缺失的一环。
典型后果:
-
monolog/monolog从2.10.2升到3.0.0,导致日志 handler 接口变更 -
guzzlehttp/guzzle因依赖链变化降级到7.2.0,触发已修复的 DNS 缓存 bug - 安全扫描工具无法比对历史基线,SCA 告警失效
库项目(供别人 require 的 PHP 包)才不提交 composer.lock,因为它的依赖应由下游决定。应用项目一旦忽略它,就等于把版本决策权交给了网络延迟、Packagist 缓存状态和 Composer 求解器当天的心情。

















