2. composer.json 深度解析:详解 require、require-dev、autoload、scripts 等配置项
说实话,很多 PHP 开发者把 composer.json 当成一个「填名字和版本号」的配置文件。我以前也这么干过,直到有一次线上环境因为 autoload 配置写错,导致类加载失败,排查了整整一个下午。嗯,从那以后,我每次写 composer.json 都会仔细过一遍每个字段。
这一章,咱们就把 composer.json 里最核心的几个配置项掰开揉碎讲清楚。你想想看,搞懂了这些,你才算真正掌握了 Composer 的命脉。
2.1 require:项目的「硬依赖」
require 字段定义的是项目必须安装的依赖包。说白了,少了它们,你的项目就跑不起来。
{
"require": {
"php": ">=8.1",
"laravel/framework": "^10.0",
"monolog/monolog": "~2.0"
}
}
这里有几个版本约束的写法,我简单说一下:
- 精确版本:
1.0.0,只安装这个版本,不推荐,太死板 - 波浪号 ~:
~2.0表示 >=2.0.0 且 <3.0.0,适合小版本升级 - 脱字符 ^:
^10.0表示 >=10.0.0 且 <11.0.0,我个人最常用这个
^ 约束,既能拿到安全更新,又不会因为大版本升级而炸掉。对于工具类库,比如 monolog,用 ~ 更稳妥。
2.2 require-dev:开发环境的「专属工具」
require-dev 里的包,只在开发环境安装。生产环境用 composer install --no-dev 就能跳过它们。
{
"require-dev": {
"phpunit/phpunit": "^10.0",
"mockery/mockery": "^1.5",
"barryvdh/laravel-ide-helper": "^2.12"
}
}
我在项目中遇到过好几次这样的问题:有人把 phpunit 写到了 require 里,结果生产环境部署时,composer 安装了一大堆测试框架的依赖,包体积直接翻倍。你想想看,这多浪费资源?
faker 和 debugbar 都写在了 require 里。结果生产环境上线后,用户能看到调试工具栏……嗯,场面一度非常尴尬。记住:只有生产环境用不到的,才放 require-dev。
2.3 autoload:让 PHP 自动找到你的类
autoload 配置决定了 Composer 如何加载你的代码。我见过太多人直接忽略这个字段,结果每次新增类都要手动 require 一遍。
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Migrations\\": "database/migrations/"
},
"classmap": [
"database/seeds/",
"app/Legacy/"
],
"files": [
"app/helpers.php"
]
}
}
这里三种方式各有用途:
| 方式 | 适用场景 | 性能 |
|---|---|---|
| PSR-4 | 现代项目,命名空间与目录结构一致 | 按需加载,性能好 |
| classmap | 遗留代码,没有命名空间 | 一次性扫描,加载快但占用内存 |
| files | 全局函数、辅助方法 | 每次请求都加载 |
重点来了:每次修改 autoload 配置后,记得执行 composer dump-autoload。我刚开始用 Composer 时经常忘记这步,结果类一直加载失败,还以为是代码写错了。
2.4 scripts:自动化你的工作流
scripts 是 composer.json 里被严重低估的功能。说白了,它让你能在 Composer 命令执行前后,自动跑一些脚本。
{
"scripts": {
"pre-update-cmd": [
"echo '准备更新依赖...'",
"php artisan down"
],
"post-update-cmd": [
"php artisan migrate",
"php artisan cache:clear"
],
"post-install-cmd": [
"php artisan storage:link"
],
"test": "phpunit",
"check": [
"@test",
"phpstan analyse"
]
}
}
我个人习惯把常用的命令都定义成脚本。比如:
composer test直接跑测试composer check同时跑测试和静态分析- 部署时自动执行迁移和缓存清理
php artisan storage:link 特别实用。这样新同事拉完代码,执行 composer install 后,存储链接就自动创建好了,省得每次都要手动操作。
2.5 其他常用配置项
除了上面四个核心配置,还有几个字段我经常用到:
{
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"laravel": {
"dont-discover": [
"spatie/laravel-permission"
]
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mycompany/private-package"
}
]
}
这里我挑几个重点说一下:
- optimize-autoloader:生产环境建议开启,能生成优化后的类映射,提升加载速度
- sort-packages:自动按字母排序 require 里的包,代码更整洁
- repositories:当你需要引用私有包时,这个字段就是救星
preferred-install 设为 dist 能加快安装速度。但如果你在调试某个包的源码,可能需要改成 source。我一般开发环境用 dist,只有需要改 vendor 里的代码时才切到 source。
2.6 一个完整的 composer.json 示例
最后,我放一个实际项目中用到的配置,你可以参考一下:
{
"name": "mycompany/myapp",
"description": "企业级 PHP 应用",
"type": "project",
"require": {
"php": "^8.1",
"laravel/framework": "^10.0",
"guzzlehttp/guzzle": "^7.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"nunomaduro/collision": "^7.0"
},
"autoload": {
"psr-4": {
"App\\": "app/"
},
"files": [
"app/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
]
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}
嗯,这个配置基本覆盖了日常开发的大部分场景。你把它当成模板,根据自己的项目改改就能用。
记住一句话:composer.json 不是写一次就完事的。随着项目演进,依赖会变,自动加载规则会变,脚本也会变。定期 review 一下这个文件,能帮你避免很多坑。