真锁定需在composer.json中写死纯数字三位版本号(如"monolog/monolog": "2.9.1"),不带^、~、*等任何符号;改后必须运行composer update monolog/monolog同步lock文件,并提交composer.lock至git,部署时仅执行composer install。

直接在 composer.json 的 require 或 require-dev 里写死纯数字三位版本号(如 "monolog/monolog": "2.9.1"),才是真锁定;其他写法,包括带 ^、~、*、dev- 的,都不算。
怎么写才算真正锁死一个包?
Composer 对版本字符串的解析有默认规则,很多写法看似“固定”,实则允许升级。
- ✅ 正确:
"phpunit/phpunit": "9.6.15"—— 不带任何符号,只有数字和点,双引号内无空格、无修饰符 - ❌ 错误:
"phpunit/phpunit": "^9.6.15"(允许升到 9.6.x)、"phpunit/phpunit": "9.6"(不同 Composer 版本解析不一致)、"phpunit/phpunit": "dev-main"(每次update都拉最新 commit) - ⚠️ 特殊但有效:
"monolog/monolog": "dev-main#abc1234"—— 分支名 + 确定 commit hash,比纯语义版更底层,但维护成本高
改完 composer.json 后必须立刻执行什么命令?
只改 JSON 文件,不运行命令,等于没改。因为 composer.lock 没同步,composer install 仍会装旧版本。
使用ydata-profiling(前身为pandas-profiling)生成全面的数据质量报告,包含相关性分析、缺失值模式和基数检测。导出交互式HTML仪表板和JSON摘要。
- 必须运行:
composer update monolog/monolog(把monolog/monolog替换为你实际要锁的包名) - 不能运行
composer update(无参数)—— 它会重新解析整棵树,可能连带升级其他包 - 不能删
vendor/后直接composer install—— 如果composer.lock还没更新,install 仍按旧 lock 装 - 验证是否生效:
composer show monolog/monolog输出应只有一行versions : 2.9.1;再跑一次composer update monolog/monolog,若提示Nothing to install or update,才算锁住
为什么 composer.lock 必须提交到 Git?
composer.json 是“意向”,composer.lock 才是“契约”。没有它,composer install 就退化成按 JSON 重解析依赖树。
- CI/CD 流水线或新同事执行
composer install时,完全忽略composer.json的约束,只认lock里的版本 - 如果
composer.lock被删、被.gitignore忽略,或没提交,就可能装上2.9.2(尤其镜像源缓存了新版本) - 上线前可加保险:
composer install --locked—— 它会校验lock中每个版本是否仍满足composer.json的约束,不满足直接报错退出 - 检查是否真锁死:打开
composer.lock,搜索包名,确认"version"字段是你写的完整版本字符串,且"source"下的"reference"是确定的 commit hash
最常被忽略的是:锁定了直接依赖,却放任间接依赖漂移。比如 laravel/framework 升级后悄悄带进 psr/log: ^3.0,而你的代码只兼容 ^2.0。这种问题不会在 composer show 里暴露,得靠 conflict 字段硬控,或定期 composer outdated --direct + --all 对比。










