Composer update vendor/package 不会降级,因其默认只升不降,将版本约束视为最低可接受版本;需用 composer require vendor/package:1.2.3 --with-all-dependencies 或改 composer.json 后加 --with-all-dependencies 才能强制降级。

为什么 composer update vendor/package 不会降级?
Composer 默认只升不降——它认为你写的版本约束(比如 "^2.0")是“最低可接受版本”,只要当前装的是 2.5.0,就不会主动切回 2.1.0,哪怕你改了 composer.json 也没用。这不是 bug,是设计逻辑:它优先满足“最新兼容”,而非“你想要的那一个”。
- 直接运行
composer update vendor/package只会升级到满足约束的最新版,不会回退 - 改完
composer.json后不加参数执行composer update,也可能被跳过——因为 Composer 发现“当前已满足”,连解析都省了 - 想让它动,必须显式告诉它:“我要这个具体版本”,且让依赖图重算
降级失败时先跑 composer why-not,别急着删 lock 文件
composer why-not 是唯一能告诉你“谁在拦路”的命令。它不像报错里那句模糊的 Your requirements could not be resolved...,而是列出每个禁止你降级的依赖项,比如:laravel/framework requires vendor/package: ^3.0。
- 必须写完整版本号,如
vendor/package:v1.2.3,不能写1.2.3或v1.2,否则报Invalid version string - 如果输出里反复出现某个包(比如
phpunit/phpunit和myclabs/deep-copy),大概率是 PHPUnit 某个小版本锁死了 deep-copy 的下限,而你想降的包依赖的是旧版 deep-copy - 别忽略
require-dev:测试工具、代码生成器常悄悄绑定主包版本,用composer show --dev单独查一遍
真正生效的降级操作只有两种可靠路径
所有“改 JSON + update”或“删 lock + install”的组合,本质都是为了触发依赖图重协商。但只有两种方式能稳定落地:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
-
推荐方式:用
composer require vendor/package:1.2.3 --with-all-dependencies—— 它会卸载当前版本、安装指定版、并同步调整所有传递依赖,避免子依赖冲突卡死 -
备选方式:手动把
composer.json中对应行改成"vendor/package": "1.2.3"(注意带引号、无^),再执行composer update vendor/package --with-all-dependencies;不加--with-all-dependencies极易失败 - 千万别只改
composer.json就提交——vendor/和composer.lock会不同步,下次composer update可能又把包拉回去
降级后 Class not found 或 autoload 失效?不是 Composer 的问题
这是最常被误判的环节。Composer 已成功把旧版文件放进 vendor/,也更新了 composer.lock,但 autoloader 缓存还是指向旧类路径。
- 先确认是否真装对了:
composer show vendor/package输出的versions必须是1.2.3,且vendor/vendor/package/composer.json里的version字段也是1.2.3(不是dev-main) - 运行
composer dump-autoload刷新自动加载映射;如果用了 classmap,加-o参数强制优化:composer dump-autoload -o - PHP-FPM 环境下还需重启服务,否则 opcache 仍缓存旧类定义
降级失败从来不是版本号写错了这么简单——它背后往往是 PHP 版本不匹配、conflict 字段硬限制、或某个开发依赖偷偷锁死了主包。盯住 composer why-not 的输出,再决定是调环境、松约束,还是换方案。










