composer update不是安全升级,而是重算整个依赖图,忽略composer.lock、按composer.json约束重新解析并安装最新兼容版本,可能导致http超时缩短、日志字段名变更等静默行为突变。

别直接跑 composer update,它不是“升级依赖”,是重算整个依赖图——生产环境一跑就可能出事。
为什么 composer update 后行为突变?
它不读 composer.lock,而是按 composer.json 里的约束重新拉包。哪怕只是从 guzzlehttp/guzzle 7.9.0 升到 7.9.1,也可能触发底层变更:
- HTTP 超时默认从 30s 缩短为 5s
- 日志字段名从
context改成extra -
expectExceptionMessage()匹配逻辑收紧
这些不会报错,但会在运行时静默生效。CI 通过、本地能跑,上线后才暴露。
composer outdated 才是你该先看的命令
它不改任何文件,只告诉你哪些显式依赖有新版可升,并暴露三类关键风险:
- 标有
[security]的行(如guzzlehttp/guzzle 7.8.1 → 7.8.2 [security]) - 带
!标记的主版本跳变(如symfony/console 5.4.39 → 6.4.0),说明约束已允许升 6.x,但你未必准备好 - 某包在
composer.json里写了"^2.0",但outdated不显示它——大概率被replace或require-dev干扰了依赖图
如果输出为空,先检查是否启用了 "minimum-stability": "stable" 和 "prefer-stable": true,它们会过滤掉所有预发布版本。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
升一个包,为什么子依赖没动?
默认行为就是如此:composer update vendor/package-name 只更新该包本身,不碰它的子依赖。比如 guzzlehttp/guzzle 依赖的 psr/http-message 还卡在 1.0.1。
- 要连带更新直系依赖:用
composer update guzzlehttp/guzzle --with psr/http-message - 要彻底更新整棵依赖树(含子依赖的子依赖):用
composer update guzzlehttp/guzzle --with-all-dependencies -
--with-dependencies在 Composer 2.2+ 已被移除,执行会直接报错Unrecognized option: --with-dependencies
注意:如果该包被其他包硬依赖某个旧版本,Composer 会报冲突,不能强制覆盖。
主版本升级必须手动改约束
composer update 绝对不会跨主版本升级,除非你先改 composer.json。比如想把 monolog/monolog 从 2.x 升到 3.x:
- 把
"monolog/monolog": "^2.0"改成"monolog/monolog": "^3.0" - 再运行
composer update monolog/monolog - 改完后
composer.lock一定会变,记得提交,否则队友composer install还是旧版
框架升级(如 Laravel 9 → 10)更是如此:不仅要改约束,还要确认 PHP 版本、检查废弃 Facade、同步更新 config/app.php 等——composer update 不会替你做这些。
最常被忽略的一点:composer.lock 不是缓存,是契约。删了重生成,等于放弃对依赖一致性的控制;CI/CD 里误用 update 而非 install,会导致每次构建都拉不同版本。










