滚动新闻 →
《伤寒论》主要讨论了什么 围棋高手为什么经常考虑很远 消息:川普已否决伊朗开放霍峡求和 或再轰炸 记者爆料:川普要给习看一份敏感和约 中方急叫停 家庭中如何教育孩子尊重父母的劳动 视频拍摄为什么不能完全依赖自动曝光 大陆影视寒冬下 台湾知名演员张晨光今年零戏约 开封为什么曾经是世界级大城市 “川习会”清单:谈贸易、伊朗和AI  未提台湾 中秋节后月饼成饲料 回收价800元一吨 小房间如何利用镜子增加视觉空间 家庭聚餐为什么成为中国饮食文化的重要部分 男子驾砂石车掉落金针山谷 家属寻获已死亡 土星卫星传重大科学发现 协助探索太空生命 短途旅行是否有必要选择高档酒店 发动机机油为什么会越来越少 美国佛州登革热病例激增 三县进入紧急状态 新能源汽车为什么需要防止电池热失控 名古屋MIRAI TOWER传火警冒烟雾 幸无人伤亡 五金工具买套装还是单独购买 《情深深》四主角隔空同框?苏有朋童年创伤曝光 AI 模型加载到 GPU 的过程是怎样的,从磁盘文件到显存完整解释 Google Cloud Managed Instance Group 是什么,多台虚拟机如何统一管理 熊本接连地震 台积电熊本厂所在地菊阳町3级 SaaS 权限系统怎么设计?管理员、员工和普通用户应该如何划分 习近平访美踉跄上机 回国最后一幕露馅 俄罗斯攻欧?丹麦警告 普京否认 显卡风扇不转是不是显卡坏了?不同显卡的风扇停转机制需要区分 川普为何高规格接待习?媒体人一句话揭迷底 老妇夜宿国3服务区 帐篷离奇倒塌死亡逾10小时 大陆高学历求职百态 95后硕士当河马“铲屎官” 江苏男殡仪馆卖咖啡 直言:挣钱“胆子要大” Windows 11 电源模式怎么选择?性能、平衡和节能应该怎样取舍 PHP autoload 怎么工作?从 Composer 自动加载理解现代 PHP 项目 泰国曼谷豪雨酿淹水灾情 居民困车阵 从项羽本纪看失败者的文学魅力 中秋节广东发生酒驾车祸 致夫妻双亡 秋天瓜子上市 “嗑”瓜子有这些好处 《伤寒论》在传统医学史上的地位 中国歌手刘欢中秋节去世 “不死癌症”等多病缠身

Composer install 和 composer update 有什么区别?实际开发中应该怎样选择

发布时间: 2026-09-25 05:00:02    最后更新: 2026-09-26 06:35:36    阅读:19  约11 分钟阅读     

在PHP项目中,Composer最容易被误解的地方之一,就是把composer install和composer update都理解成“把依赖包装上或者更新一下”。

实际上,这两个命令处理的是完全不同的问题。

composer install解决的是“按照项目已经确定的依赖版本,把运行环境恢复出来”;composer update解决的是“重新计算依赖关系,并决定项目下一组应该使用什么版本”。

这一区别看起来只是两个命令,实际上直接关系到生产环境稳定性、团队协作、CI/CD部署以及依赖升级风险。

Composer的核心文件有两个:composer.json和composer.lock。

composer.json描述的是项目允许使用什么依赖。例如:

{
"require": {
"monolog/monolog": "^3.0",
"guzzlehttp/guzzle": "^7.0"
}
}

这里的^3.0和^7.0并不是具体安装版本,而是版本约束。它告诉Composer哪些版本符合项目要求。

真正记录“这一次项目到底安装了哪些版本”的,是composer.lock。

例如:

monolog/monolog 3.9.0
guzzlehttp/guzzle 7.9.3
psr/log 3.0.2

这就是Composer设计中非常重要的两个层次:composer.json描述“允许什么”,composer.lock描述“已经决定使用什么”。

所以,当一个项目已经存在有效的composer.lock时,开发者从Git仓库拉取代码后,通常应该执行:

composer install

Composer会读取composer.json,同时使用composer.lock中已经确定的精确版本安装依赖。这样开发机、测试服务器、CI环境和生产服务器就可以使用同一套依赖版本。Composer官方文档也明确建议应用项目将composer.lock提交到版本控制系统,以保证不同环境使用一致的依赖版本。

这里有一个非常重要的细节。

composer install并不是“永远不会更新任何东西”。

如果项目没有composer.lock,Composer需要根据composer.json重新解析依赖并生成lock文件。换句话说,新项目第一次初始化时,可能需要通过依赖解析得到一套版本并产生composer.lock。之后这个lock文件才成为稳定安装的依据。

因此,更准确的理解是:

有composer.lock时,install主要负责复现已经锁定的依赖环境。

没有composer.lock时,install需要先进行依赖解析并生成lock文件。

而composer update的性质完全不同。

执行:

composer update

Composer会重新读取composer.json中的版本约束,对整个依赖树进行重新求解,然后选择当前约束范围内符合条件的版本,并把新的精确版本写入composer.lock。之后Composer会安装这些解析出来的依赖。

例如:

"guzzlehttp/guzzle": "^7.0"

并不意味着永远使用7.0.0。

如果lock文件原来锁定7.7.0,而当前存在符合约束的7.x新版本,那么执行完整的:

composer update

就可能导致Guzzle以及它的部分依赖发生变化。

这里的关键并不是“Composer自动找最新版本”,而是“重新进行依赖求解”。

因为依赖关系通常不是一棵简单的树,而是一张复杂的依赖图。

假设你的项目直接依赖A和B:

项目
├── A
│ └── C ^2.0
└── B
└── C ^2.3

Composer需要找到一个同时满足A、B以及其他所有依赖约束的C版本。

如果某个包的新版本改变了依赖要求,Composer的求解器就可能重新调整整个依赖图中的某些版本。

所以composer update绝不仅仅是“下载新版本”。

它实际上是在重新计算项目的依赖闭包。

这也是为什么生产服务器通常不应该直接执行:

composer update

如果生产环境已经部署了经过测试的composer.lock,直接update相当于在生产机器上重新打开依赖版本选择器。

你原来测试的是一组明确版本,生产服务器却可能得到另一组版本。

这会让生产环境出现一个非常麻烦的问题:代码仓库是同一个,但运行结果却不一定相同。

而:

composer install --no-dev --optimize-autoloader

则更加符合典型生产部署场景。

它的核心思路是:代码版本已经确定,依赖版本也已经通过lock文件确定,现在只是把这套经过测试的环境部署出来。

对于团队开发也一样。

假设开发人员A修改了PHP代码,开发人员B刚刚更新了依赖。如果B执行了:

composer update

然后把新的composer.lock提交到Git,那么团队其他成员拉取代码之后执行:

composer install

就会得到B已经解析并提交的那一整套依赖版本。

因此,composer.lock并不是一个应该“尽量少碰”的普通配置文件。

它是应用项目依赖环境的一部分。

真正应该避免的是未经测试的lock文件变化,而不是正常维护lock文件。

当你确实需要升级依赖时,应该主动更新它,然后测试,再提交。

例如项目需要升级某个包,不必每次都执行整个:

composer update

可以指定目标包:

composer update guzzlehttp/guzzle

Composer支持针对特定包进行更新,这可以明显缩小依赖变化范围。官方文档也提供了针对单个或多个包更新的方式。

如果项目规模较大,这种做法尤其重要。

因为一次完整的依赖更新可能涉及几十甚至上百个间接依赖,而单独更新一个直接依赖通常更容易审查变化。

还可以使用:

composer update -m

也就是--minimal-changes,要求Composer尽量保持现有lock版本,只进行必要的依赖变化。对于希望控制更新范围的项目,这类选项非常有价值。

另一个常见错误是认为“有了composer.lock,就完全不用检查composer.json”。

实际上两者必须保持逻辑一致。

可以使用:

composer validate

检查composer.json是否合法,同时检查lock文件是否与项目配置保持同步。Composer官方也建议在提交composer.json以及适用的composer.lock之前运行这个命令。

开发者还应该区分“更新Composer”和“更新项目依赖”。

:

composer self-update

更新的是Composer自身。

:

composer update

更新的是当前项目的PHP依赖。

这两个动作完全不是一回事。

如果项目出现依赖问题,也不要一上来就删除composer.lock。

例如:

rm composer.lock
composer update

会彻底改变依赖解析结果,这有时候可以作为排查手段,但不应该成为日常维护方法。

对于生产环境尤其危险,因为你可能只是想解决一个包的问题,却把整个依赖树重新排列了一遍。

真正专业的依赖维护流程通常应该是这样的。

开发人员修改composer.json或者通过:

composer require vendor/package

引入新的直接依赖。

Composer完成依赖解析并修改composer.lock。

然后运行项目测试、静态分析、代码检查以及必要的集成测试。

确认没有问题后,把composer.json和composer.lock一起提交。

CI环境通过:

composer install

从lock文件恢复完全一致的依赖环境。

生产部署继续使用:

composer install --no-dev --optimize-autoloader

这样依赖版本的决定发生在开发和测试阶段,而不是发生在生产服务器上。

安全维护则是另外一件事情。

如果只是想检查依赖是否存在已知安全问题,可以使用:

composer audit

而不是为了“看看有没有安全更新”就直接执行完整的composer update。

对于大型项目,还可以使用:

composer outdated

查看哪些依赖存在可用更新,然后逐项评估,而不是把整个依赖树一次性升级。

这里还有一个非常重要的例外:PHP库项目。

Composer官方对应用和可复用库的lock文件处理方式并不完全相同。对于一个最终运行的应用程序,提交composer.lock通常是推荐做法;对于一个供其他项目依赖的库,lock文件不会决定下游项目最终安装什么版本,因此它的作用完全不同。

所以不能简单地说“所有Composer项目都必须提交composer.lock”。

更准确的原则是:应用项目通常应该提交,库项目则根据开发和测试需求决定。

如果把整个过程压缩成一句话,可以这样理解:

composer.json决定“允许安装什么版本”,composer.lock决定“这次项目已经选定什么版本”,composer update负责重新做这个选择,而composer install负责把已经选择好的依赖恢复出来。

这也是为什么成熟项目通常不是“开发时一直composer update,部署时再看看能不能跑”,而是把依赖升级本身当作一次需要测试、审查和回滚准备的代码变更。

Composer真正解决的问题,从来不只是帮PHP开发者下载几个第三方包,而是把一个复杂的依赖关系图变成可以重复构建、可以审计、可以部署、可以回滚的确定性软件环境。

当composer.lock被认真对待以后,开发环境、测试环境和生产环境之间的差异会大幅减少。对于PHP项目来说,这往往比单纯追求“依赖永远是最新版本”更加重要。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

分享 Facebook | X | WhatsApp | LinkedIn

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP