composer install不装新require的包是因为它只依赖composer.lock,忽略composer.json变更;必须运行composer update foo/bar将新包写入lock,而非直接install。

composer install 为什么死活不装我刚 require 的包
不是 Composer 拒绝你,是 composer.lock 在拦路。它记录的是上一次 composer update 算出来的完整依赖树,而 composer install 默认只认 lock 文件,完全忽略 composer.json 里新增或改过的行。
常见现象:你刚执行了 composer require foo/bar:2.5.0,composer.json 确实多了这行,但紧接着 composer install 却没装、也没报错,甚至显示 Package operations: 0 installs, 0 updates, 0 removals。
- 先确认是否真没写进 lock:运行
composer show foo/bar,如果提示Package not found,说明 lock 里确实没有 - 此时必须运行
composer update foo/bar(带包名),而不是composer install—— 后者不会重算,前者才会把新包及其兼容子依赖写入 lock - 别用
composer update(无参数):它会连带更新其他所有包,可能引入意外变更 - 改完
composer.json后不跑update,等于白改;提交前不git diff composer.lock,等于埋雷
本地调试时 “Your requirements could not be resolved” 怎么快速定位
这个错误不是网络问题,也不是权限问题,是 Composer 的 SAT 求解器明确告诉你:当前所有约束条件无法同时满足。别删 vendor、别换镜像,先问清楚谁在卡脖子。
- 第一步,用
composer why-not vendor/package:version,比如composer why-not laravel/framework:^11.0。输出的最后一行才是根因,要倒着读——从 “because your project requires…” 开始,逐层看哪一行带(conflict with ...) - 第二步,如果输出里出现
orchestra/testbench或phpunit/phpunit,大概率是它们内部硬绑了旧版illuminate/support,和你要升的 L11 冲突 - 第三步,临时注释掉
require-dev里非核心的包(比如laravel/pint、php-cs-fixer),再跑composer update --dry-run看是否通过 - 加
-vvv会输出完整依赖树,但信息过载;优先用composer prohibits vendor/outdated-package反向查谁拖了后腿
本地 PHP 版本低,但想装高版本包调试怎么办
别用 --ignore-platform-reqs。它只是把报错从安装阶段推迟到运行时——比如本地 PHP 7.4 装了 Laravel 11,代码里一用 match 表达式就直接 Fatal error。
- 正确做法是用
config.platform.php告诉 Composer:“我目标环境是 PHP 8.1”,让它按这个版本去选包:"config": { "platform": { "php": "8.1.28" } } - 设完必须立刻执行
composer update --lock,否则 lock 文件仍记录旧平台下的解析结果 - 验证当前 Composer “认为”的 PHP 版本:运行
composer show --platform,不是php -v - 注意:platform 配置对
require-dev同样生效。如果你本地开发依赖 PHP 8.3 特性,但 platform 锁死在 8.1,phpunit/phpunit可能被降级到不支持enum的旧版
怎么让本地调试用新版,但上线锁死旧版
Composer 不支持 if-else 式的环境分支依赖。所谓“本地调试用新版”,本质是拆分用途 + 控制安装时机,不是靠 magic 配置实现的。
- 把调试专用包(如
symfony/var-dumper、barryvdh/laravel-debugbar)全放require-dev,生产部署时加--no-dev,它们就不会进vendor/autoload.php - 若某个包既要在本地调试用、又需在生产运行(比如日志增强 SDK),就不能放
require-dev,得在代码里用class_exists()或extension_loaded()做运行时判断 - 真正锁死版本,靠的是三件事缺一不可:
"foo/bar": "2.11.0"(三位纯数字)、composer update foo/bar(写入 lock)、composer install(只读 lock) - CI 流水线必须用
composer install --no-dev,但本地开发机不该加这个参数——否则 IDE Helper、测试工具全失效,反而降低调试效率
最常被忽略的一点:lock 文件不是保险柜,是快照。它只保证“当时能跑”,不保证“永远可用”。Packagist 下架、作者标记 abandoned、PHP 主版本升级,都可能让昨天有效的 lock 今天就装不上。调试时别只盯着自己改的那行,先看 composer show --platform 和 composer why-not 输出的拒绝链末端。











