composer.lock 是 Composer 依赖的权威声明式快照,由 composer update 生成,必须提交且不可手动修改;它包含 checksum、dist URL、完整依赖树及 platform 配置,是 CI 环境重建和生产部署的唯一可信依据。

composer.lock 不是“导出”出来的,它是 composer update 运行后自动生成的权威快照;你不需要导出它,只需要确保它存在、被提交、且未被意外修改。
为什么不能用 composer show 替代 composer.lock 查依赖状态
composer show 读的是 vendor/ 目录下真实安装的包,反映当前运行时状态;composer.lock 是声明式快照,含 checksum、dist URL、完整嵌套依赖树和 platform 配置。两者可能不一致——比如手动删过 vendor/ 但没重装,或 composer install 被跳过。
- CI 流水线必须基于
composer.lock恢复环境,不是靠composer show输出重建 -
composer show --locked只是“模拟读取 lock”,实际仍走installed.json,无法验证哈希或 dist 完整性 - 想查某包是否在 lock 中锁定?用
jq '.packages[] | select(.name == "monolog/monolog")' composer.lock,别信composer show的实时结果
composer show --locked 的真实行为和陷阱
这个参数并不读取 composer.lock 文件本身,而是让 composer show 在“假装 lock 已生效”的上下文中运行——它仍从 vendor/composer/installed.json 加载数据,只是禁用了一些 dev-only 包的显示逻辑。
- 加了
--locked后,composer show --format=json输出的版本号可能和composer.lock里不一致(尤其当 vendor 被手工改过) - 它不会校验 package checksum,也不检查
dist.reference是否匹配 git commit - 真正需要 lock 级别信息时,直接解析
composer.lock更可靠,例如:jq -r '.packages[] | "\(.name) \(.version)"' composer.lock | sort
提取 lock 文件里的关键字段:哪些字段必须关注
composer.lock 是合法 JSON,但结构随 Composer 版本微调(v2 → v3 改动了 packages 数组位置)。提取时优先用稳定字段:
-
.packages[].name和.packages[].version总是存在,可安全提取依赖清单 -
.packages[].license可能为null或数组(如["MIT", "Apache-2.0"]),需用jq -r '.packages[] | select(.license != null) | "\(.name)\t\(.license[])"' -
.platform.php和.config.platform.php影响兼容性判断,还原环境前必须核对 - 别碰
.packagesDev字段:v2 和 v3 对 dev 包的存放位置不同,脚本会断
备份与校验 composer.lock 的实操要点
它不是“可选配置”,是生产部署的契约文件。备份动作就是复制文件,校验动作就是比对哈希或 diff 内容。
- 备份命名建议:
composer.lock.20260421,而非composer.lock.bak(容易被 .gitignore 忽略) - CI 中校验 lock 是否被绕过:在
composer install前加一步diff composer.lock (需安装 jq) - Git 提交前检查:运行
composer update --dry-run,若输出非空,说明composer.lock和composer.json不一致,不能直接提交 - 团队协作中,禁止
composer install --no-lock,该参数会让 lock 失效,等同于放弃依赖确定性
真正难的不是提取字段,而是理解 composer.lock 是一个带约束条件的安装说明书——它的每一行都可能影响 PHP 版本兼容性、扩展加载顺序、甚至 autoloader 行为。别把它当普通 JSON 解析完就完事。











