唯一可靠降级动作是composer require vendor/package:1.2.3 --with-all-dependencies,它强制重装指定旧版本并同步调整全部子依赖;composer无downgrade命令,update默认只升不降且不支持带版本号参数,直接改composer.json后运行update无效。

composer require vendor/package:1.2.3 --with-all-dependencies 是唯一可靠降级动作
Composer 没有 downgrade 命令,composer update 默认只升不降——哪怕你写 composer update monolog/monolog:2.9.2,它会直接报错 [InvalidArgumentException] Package "monolog/monolog" is not required in your composer.json.。真正起效的只有 require 加显式版本号。
加 --with-all-dependencies 不是可选项:它强制 Composer 重算整条依赖链,同步调整所有子依赖版本,避免出现 monolog/monolog 降了但 symfony/console 还卡在 6.x 导致运行时报 Class not found。
- 先确认目标版本存在:
composer show -a monolog/monolog查2.9.2是否标记为abandoned或unstable - 执行:
composer require monolog/monolog:2.9.2 --with-all-dependencies - 验证:
composer show monolog/monolog输出的version必须是2.9.2.0(Composer 自动补零,2.9和2.9.2解析行为不同)
composer why-not vendor/package:1.2.3 才是冲突源头定位核心命令
报错末尾的 Conclusion: don't install guzzlehttp/guzzle:^8.0 是求解器放弃后的结论,不是原因。composer why-not 才能穿透嵌套依赖,输出真实阻断链——而且必须带完整版本标识,漏掉 : 或版本号会报 Package not found。
输出要从下往上读:最后一行是你 composer.json 的根声明(比如 myapp/core dev-main requires guzzlehttp/guzzle (^6.5)),往上每行都是某个已安装包写的约束。常见陷阱是看到 laravel/sanctum 出现在链里就忽略,其实它可能悄悄锁死了 guzzlehttp/guzzle 的上限。
- 若输出为空,说明该版本不在当前 Packagist 通道(比如你设了
"minimum-stability": "stable",但目标版本是dev分支) - 若某行带
conflict with foo/bar (>=2.0),那是foo/bar自己声明的规则,Composer 只是照章办事 - 注意
require-dev包也参与解析——phpunit/phpunit的 PHP 版本要求可能把整个链拖死在 5.x
composer install 不装旧版?先确认你在用哪个 composer.lock
很多人以为 composer install 应该按 composer.lock 装旧包,结果 vendor/ 里还是新版本,甚至报 Class not found。根本原因是:你根本没在用目标历史版本的 composer.lock。
composer.lock 文件被改过却不自知很常见。运行 git status composer.lock,如果显示 modified 或 not staged,说明它已被覆盖或手动编辑过,校验和(content-hash)已失效,install 会拒绝执行或跳过校验直接走解析流程。
- 若旧版
composer.lock已提交,直接恢复:git checkout abc1234 -- composer.lock(abc1234是含旧 lock 的提交哈希) - 删干净
vendor/:rm -rf vendor(Windows 用户请手动删除) - 再跑
composer install——此时它才真正只读 lock、不碰composer.json的版本约束 - 别用
composer update --lock,它只是重写 lock,不会清理vendor,也不会回退任何代码
降级后 autoload 断裂比版本冲突更隐蔽
降级成功不代表能跑通。Laravel 10 升级后 App\Providers\AppServiceProvider 找不到,常被误判为 Autoload 问题,其实是 PSR-4 映射残留;Monolog 3 降回 2.x 后 StreamHandler::setFormatter() 报 Method not found,是代码没适配 breaking change,不是 Composer 装错了。
关键检查点只有三个:vendor/autoload.php 是否存在且可读、composer.lock 中该包的 dist/sha256 是否匹配、PHP 平台版本是否与目标包兼容(比如 config.platform.php 设了 "8.2",但 monolog/monolog:2.9.2 只支持 ^7.2 || ^8.0)。
- 执行
composer dump-autoload -o强制刷新映射,尤其当包内目录结构变动时 - 运行
php -r "require 'vendor/autoload.php';"验证 autoload.php 是否能加载 - 查官方
UPGRADE-2.0.md(不是 CHANGELOG),它明确列出要改哪些类、方法、命名空间











