install是照着composer.lock一模一样装,update是扔掉composer.lock重算依赖树;install仅在无lock时退化为update行为生成锁文件,否则不生成也不修改;update默认全量重算依赖,非仅更新改动包。

直接说结论:install 是照着 composer.lock 一模一样装,update 是扔掉 composer.lock 重算一遍依赖树——用错一个,线上就可能挂。
为什么 composer install 有时会生成 composer.lock?
它不是“偶尔生成”,而是行为由文件是否存在决定:
- 有
composer.lock→ 完全跳过composer.json的版本约束,只按锁文件里写死的版本号、哈希、源地址下载解压 - 没有
composer.lock→ 自动 fallback 到composer update行为:读composer.json、跑依赖求解器、生成新锁文件
所以新人克隆项目后执行 composer install 看到锁文件“突然出现”,不是 bug,是预期行为。但这个首次生成的结果,和你本地手动跑 composer update 不一定相同——比如对 dev-main 分支的处理倾向不同。
composer update 真的只更新你改过的包吗?
不。默认它会重新计算整个依赖图,哪怕你只在 composer.json 里加了一行 "monolog/monolog": "^3.0",也会连带升级 symfony/polyfill、psr/cache 这类间接依赖。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 想只更新某个包:
composer update monolog/monolog - 想更新某类包:
composer update symfony/* - 加
--with-all-dependencies才会连带更新子依赖;不加,可能卡在“已满足”状态,导致底层 polyfill 没升,上线后出问题 - 执行前必做:
composer update --dry-run,先看清会动哪些包、升到什么版本
生产环境为什么死守 composer install --no-dev?
因为 install --no-dev 是“复现”,而 update --no-dev 仍是“重算”:
-
install --no-dev:跳过require-dev包,且完全跳过依赖解析——只按composer.lock里写死的哈希和 URL 下载归档,快、确定、可预测 -
update --no-dev:仍会联网请求 Packagist API、校验 PHP 版本/扩展/所有子依赖约束,本质是 NP-hard 计算,50 个包可能卡两分钟;只是最后不装 dev 包而已 - CI/CD 流水线或 Docker 构建中出现
composer update,等于把构建结果交给网络延迟和镜像同步状态——凌晨告警经常就来自这儿
composer.lock 不提交 Git 会怎样?
它不是缓存,是契约。删掉或忽略它,等于放弃所有环境一致性保障:
- Git 忽略
composer.lock→ 每个人composer install得到的是不同时间点的随机快照 - 有人删了锁文件再提交 → 其他人
install就退化成update,环境漂移从此开始 -
composer install从不检查远程是否“过期”,它无条件信任锁文件——依赖是否该升,只能靠人主动update并验证
最易被忽略的一点:很多人以为 install 会自动同步到最新,其实它连远程都不查。锁文件一旦损坏或与当前 PHP 环境不匹配(比如 lock 里锁的是 PHP 8.1 专属版本,而你在 8.2 下运行),install 可能直接跳过某些包,或报 Your requirements could not be resolved。










