直接写死纯数字版本号(如"monolog/monolog": "2.9.1")或使用等号语法(如"=2.9.1")是唯一可靠锁定方式;必须同步执行composer update vendor/package更新composer.lock,并提交该文件至Git,CI部署须用composer install --locked确保环境一致。

直接写死版本号是唯一可靠方式
Composer 没有“禁止升级”的开关,所谓“锁定”本质就是让解析器失去选择空间。只要 composer.json 里某个包的版本约束不含 ^、~、* 或任何范围运算符,它就只能装那个精确版本。
常见错误是以为 "2.9" 或 "2.9.0" 就够了——但 Composer 会把它当作 ~2.9.0 解析(尤其在旧版中),仍允许 patch 升级。必须确保是纯数字字符串,不带任何隐式含义。
-
"monolog/monolog": "2.9.1"✅ 安全,只接受该 exact 版本 -
"monolog/monolog": "=2.9.1"✅ 更显式,等号语法强制忽略所有 SemVer 规则 -
"monolog/monolog": "^2.9"❌ 允许升到 2.99.9 -
"monolog/monolog": "2.9.*"❌ 匹配 2.9.0–2.9.999
改完必须同步更新 composer.lock
只改 composer.json 不生效。Composer 不会自动重写 composer.lock,你得手动触发一次 composer update vendor/package,否则 lock 文件里还存着旧的解析结果,composer install 仍可能按旧逻辑装包。
验证是否真正锁住:
- 运行
composer show vendor/package,输出版本必须和composer.json一致 - 再跑
composer update vendor/package,应返回Nothing to install or update - 检查
composer.lock中该包的version字段,值必须和composer.json完全相同(包括等号)
--locked 参数不是替代方案,而是兜底校验
composer install --locked 不是用来“实现锁定”的,它是上线前最后一道防线:强制要求 composer.lock 中每个包的版本都满足 composer.json 的约束。如果 lock 里是 "laravel/framework": "11.0.0",而 json 写的是 "^10.0",它会报错退出。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
但它不解决“为什么 lock 里是 11.0.0”这个问题——那得靠你提前用精确版本约束+手动 update 来控制。
- CI 部署命令必须含
--locked,否则镜像源缓存或网络抖动可能导致降级或误升 -
--locked和--dry-run互斥,不能一起用 - 若本地没提交最新 lock,CI 执行
--locked会直接失败,这反而是好事——暴露了流程漏洞
团队协作中最容易被忽略的点
单人开发时写死版本看似简单,但多人协作下,真正的风险不在怎么写,而在谁来保证它不被绕过。
composer.lock 被 .gitignore、漏提交、或 CI 构建时用 composer update 替代 install,都会让所有版本约束形同虚设。一旦 lock 缺失,composer install 就退化成按 composer.json 重新解析——哪怕你写了 "=2.9.1",如果源里该版本已删,它甚至可能装不上。
所以硬编码版本约束必须配合两个动作:把 composer.lock 提交进 Git;CI 脚本里禁用 composer update,只用 composer install --locked --no-dev --no-interaction。

















