require字段声明项目运行必需的依赖,无论是否加--no-dev都会安装;require-dev仅用于开发,加--no-dev则完全跳过;版本约束错误会导致装错版本而非装不上;require变动后须显式运行dump-autoload更新自动加载映射。

require字段只影响安装时的依赖解析,不区分环境
Composer 的 require 字段本身没有“生产环境”或“开发环境”的语义——它声明的是项目**运行所必需的最低依赖集合**。哪怕你只在 CLI 工具里用到某个包,只要代码执行流会经过它,就该放 require;反之,像 phpunit 这类仅用于测试的工具,必须进 require-dev。
常见错误现象:composer install --no-dev 后程序报 Class not found,结果发现本该在 require 里的 monolog/monolog 被误塞进了 require-dev。
-
require里的包,无论composer install还是composer install --no-dev都会被安装 -
require-dev里的包,默认会被安装,但加--no-dev就完全跳过(包括其递归依赖) - 如果某包既被
require又被require-dev引入,以require的版本约束为准
版本约束写法直接决定能否装上、装哪个版本
写错约束不是“装不上”,而是“装了错的版本”——比如 "guzzlehttp/guzzle": "^7.0" 和 "guzzlehttp/guzzle": "7.0" 看似差不多,实际前者允许 7.9.0,后者只认严格等于 7.0.0(且 Composer 会拒绝安装,因为没这个 exact 版本)。
使用场景:线上部署要求稳定,应避免 dev-master 或 @dev;CI 流水线跑测试可能需要锁定 minor 版本防止意外升级。
-
"foo/bar": "^1.2.3"→ 允许1.2.3到1.x.x(不含2.0.0),推荐日常使用 -
"foo/bar": "1.2.*"→ 允许1.2.0到1.2.999,比^更窄,适合有 patch 级兼容问题时 -
"foo/bar": "dev-main as 1.0.0"→ 仅调试用,禁止上线,composer install --no-dev会直接失败
require 中的包若含 autoload 配置,会影响整个项目的类加载路径
某些包(比如 Laravel 的 illuminate/support)在自己的 composer.json 里写了 "autoload": {"psr-4": {"Illuminate\": "src/"}},一旦你把它放进 require,Composer 就会在 vendor/autoload.php 里注册这个命名空间——哪怕你一行 Illuminate\ 的代码都没写。
容易踩的坑:本地开发正常,上线后报 Class 'Illuminate\Support\Str' not found,查半天发现是 require 里漏了 illuminate/support,但更隐蔽的问题是:它被另一个已引入的包间接依赖,而那个包在 require-dev 里,--no-dev 后整个 autoload 链就断了。
- 用
composer show -t查看依赖树,确认关键包是否真被require直接声明 - 运行
composer dump-autoload --optimize不会修复缺失的 require,只会加速已有 autoload 规则 - 如果一个包只提供函数(如
ramsey/uuid的全局函数),它仍需进require,否则函数不可用
require 更新后不运行 dump-autoload,新类可能无法自动加载
很多人改完 composer.json 的 require 就直接 composer install,以为万事大吉。但 Composer 默认不会重生成 autoload 映射——尤其当你新增了一个 PSR-4 命名空间,或某个包更新后调整了源码目录结构时,vendor/autoload.php 里还是旧规则。
性能影响:频繁执行 dump-autoload 没必要,但每次 require 变动后至少要跑一次 composer dump-autoload(或让 install/update 自动触发)。
-
composer install和composer update默认会调用dump-autoload -
composer require foo/bar也会自动触发,但手动改composer.json后必须显式运行composer dump-autoload - 加
--optimize参数可生成 classmap 提升加载速度,但会忽略files类型的 autoload(比如全局函数文件)
最常被忽略的其实是 require 的“传递性”:你删掉一个包的 require,不代表它的子依赖就自动消失——Composer 只保证顶层声明的包存在,其余由依赖图自动收敛。所以别靠删 require 来“精简 vendor”,得用 composer prohibits 或 composer depends 反查谁还赖着它。










