先运行composer why-not laravel/framework:^10.0定位阻塞包,再显式执行composer update laravel/framework --with-dependencies,避免全量更新引发依赖错位,升级后核对composer.lock变更范围。

旧项目升级不是“换几个版本号”就能过的事,Composer 会直接卡在 Resolving dependencies 或报 Your requirements could not be resolved —— 它不是算得慢,是根本找不到满足所有约束的解。
先搞清谁在封杀目标版本,别瞎改 composer.json
报错里只写 Conclusion: don't install laravel/framework:^10.0,但没说谁拦的。这时候敲 composer why-not laravel/framework:^10.0 才是正解。它的输出是“拒绝理由链”,必须从最后一行倒着读:
- 最后一行通常是你的根项目
myapp/myproject dev-main,它声明了某个依赖(比如guzzlehttp/guzzle)的旧范围 - 往上一行可能是某个私有 SDK 或
require-dev包(如phpunit/phpunit)锁死了该依赖的版本 - 如果某行末尾带
(conflict with foo/bar >=2.0),说明foo/bar自己写了conflict字段,Composer 是照章执行
升级要定点,别用全量 update 拉垮整个 vendor
composer update 默认重算全部依赖,容易把线上稳定的 symfony/polyfill-*、psr/log 全带偏。真要升框架或核心包,必须显式指定:
- 写法必须是
composer update laravel/framework --with-dependencies,不能带引号、不能加^或~ -
--with-dependencies是关键:它只允许升laravel/framework所需的最小依赖集,比如guzzlehttp/guzzle和symfony/http-foundation,但不会动phpunit/phpunit - 升级后立刻
git diff composer.lock,确认只有预期包及其直系依赖被改;多出一个monolog/monolog都可能埋运行时隐患
PHP 版本不匹配不是网络问题,是硬性拦截
报 requires php ^8.1 but your php version is 7.4.33,这不是 Composer 故意卡你,而是它用当前 shell 的 php -v 结果去校验约束。常见误操作:
- 以为切系统 PHP 就行,结果 CI 脚本里
php -v还是 7.4 - 加
--ignore-platform-reqs强装,结果vendor/里塞进 PHP 8.1 语法(比如match表达式),一跑就ParseError - 改了
composer.json里的"php": "^8.1"却没跑composer update --lock,导致composer.lock还记着旧包
正确做法是明确指定 PHP 二进制路径执行:/usr/bin/php8.1 composer install(Linux/macOS)或 "C:\php\php81\php.exe" composer install(Windows)。
别删 composer.lock,它是唯一可信快照
composer.lock 不是障碍,是当前已验证可行的依赖快照。删它等于扔掉唯一线索,重来一遍只会更难定位。遇到冲突时:
- 先跑
composer install --dry-run,预演哪条路径断了,比盲等Resolving dependencies有用得多 - 团队协作中拉新代码后报
Root requires X but Y is installed,大概率是别人提交了新composer.json却漏提composer.lock,此时应git checkout -- composer.lock恢复再装 -
^1.2.3和~1.2.3看似只是写法差异,实际决定版本范围是否有交集:^1.2.3允许所有1.x,~1.2.3只允许1.2.x—— 这个细节常让依赖图无解
复杂点在于:冲突往往藏在 require-dev 里,比如 orchestra/testbench 悄悄绑死 Laravel 9,而你主项目想升到 10。这种隐性拖拽,不靠 composer why-not 和 composer why 交叉验证,几乎没法揪出来。











