必须用composer install:多人协作、CI/CD构建、生产部署时,它严格按composer.lock还原精确版本和哈希值,确保可复现;update会重解依赖导致版本漂移和线上崩溃。

依赖管理的核心不是“装什么”,而是“谁在什么时候、以什么精度决定装哪个版本”——composer install 和 composer update 的行为差异,直接决定了项目是否可复现、是否可协作、是否会在上线时突然崩掉。
什么时候必须用 composer install,而不是 composer update
只要涉及多人协作、CI/CD 构建、生产环境部署,composer install 是唯一安全选项。它完全忽略 composer.json 里的版本“愿望”,只按 composer.lock 中记录的精确版本和哈希值还原依赖树。
-
composer update会重新运行 SAT 求解器,尝试找最新兼容组合——哪怕只改一行composer.json,也可能把guzzlehttp/guzzle从7.4.5升到7.9.0,而后者可能悄悄弃用了你正在用的HandlerStack::push()方法 - CI 流水线里漏写
--no-dev?composer install仍会装phpunit/phpunit,不仅浪费时间,还可能因sebastian/exporter版本锁死,间接卡住symfony/console更新 - 本地
composer.lock没提交?Git 拉下来的人执行composer install时,会 fallback 到composer.json解析——此时没人能保证装出来的是同一套东西
require 和 require-dev 划分错误的典型后果
错放一个包,轻则多装 30MB 无用代码,重则引发隐性冲突。关键判断标准只有一条:这个包的类或功能,是否在 PHP 进程启动后、请求处理中被实际调用?
- 进
require:所有运行时必需的,比如doctrine/dbal(迁移命令要执行)、monolog/monolog(日志写入)、laravel/framework(路由和容器) - 进
require-dev:仅开发期使用的,比如phpunit/phpunit(测试执行)、roave/security-advisories(安装时做冲突拦截,本身不提供任何类)、laravel/pint(代码格式化) - 危险中间地带:
symfony/var-dumper看似调试用,但如果你在生产环境用dd()或dump(),它就是运行时依赖;否则就该进require-dev
解决冲突时,为什么 composer why-not 比删 vendor 有用十倍
报错信息里写的 don't install guzzlehttp/guzzle:8.0.0 不是结论,只是症状。真正要找的是“谁在拦路”。composer why-not 输出的是阻塞链,从底往上读才对:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 最后一行是你自己写的
"guzzlehttp/guzzle": "^7.0"(根约束) - 倒数第二行可能是
some/package v2.1.0 requires guzzlehttp/guzzle ^6.0(间接依赖) - 再往上可能是
another/tool v1.5.0 requires some/package ^2.0(更深一层) - 如果输出为空?先检查
require-dev——很多冲突来自mockery/mockery锁着老版sebastian/exporter,进而拖死整个symfony生态
别信 composer.json 里写的“我想装啥”,用 composer show --tree | grep "guzzlehttp/guzzle" 看 lock 文件里真实拉进来的到底是哪个版本、由谁引入。
升级单个包时,--with-dependencies 不是可选项,是必须项
执行 composer update monolog/monolog 默认只更新 monolog/monolog 自身,不碰它的子依赖。但新版本 monolog/monolog:^3.0 可能要求 psr/log:^3.0,而旧 lock 文件里还锁着 psr/log:^1.0——结果就是命令成功退出,但运行时报 Class not found: Psr\Log\LoggerInterface。
- 正确做法:
composer update monolog/monolog --with-dependencies,让 Composer 主动升级其直系依赖 - 降级跨主版本(如从
^8.0切回7.4.5),必须在composer.json里写死"guzzlehttp/guzzle": "7.4.5",不能只写"^7.0",否则求解器可能选7.9.0而非你想要的修复版 - 执行后立刻
git diff composer.lock,确认改动范围可控——如果看到几十个包被修改,说明没加--with-dependencies或约束太松
最常被忽略的一点:锁文件里记录的 platform 配置(如 PHP 版本)必须和 composer.json 中 config.platform.php 一致,否则 composer install 在不同 PHP 环境下可能解析出完全不同的一套依赖。

















