composer.json 配置
composer.json 是 Composer 项目的核心配置文件,它定义了项目的元数据、依赖关系、自动加载规则和脚本命令。每一个使用 Composer 管理的 PHP 项目都必须包含这个文件。本节将深入详解 composer.json 的每个字段、版本约束格式、最小稳定性设置,并通过完整的示例展示如何编写规范的配置文件。
composer.json 概述
composer.json 位于项目根目录,是 Composer 的入口配置文件。它告诉 Composer:
- 这个项目叫什么
- 项目需要哪些依赖包及其版本
- 如何自动加载 PHP 类
- 需要执行哪些脚本命令
- 使用哪些仓库源
你可以通过 composer init 命令交互式地创建 composer.json,也可以手动创建。
核心字段详解
name — 项目名称
{
"name": "vendor/project"
}项目名称由 vendor(供应商/组织)和 project(项目名)两部分组成,用 / 分隔。
vendor— 通常是公司名或开发者名(如laravel、symfony、monolog)project— 项目或包的名称(如framework、console、monolog)
何时需要 name 字段
- 库/包(被其他项目引用)— 必须设置
name - 应用程序/项目(不被其他项目引用)—
name是可选的,但建议设置
名称一旦发布到 Packagist,就不应该再更改,因为其他项目可能已经依赖了这个名称。
description — 项目描述
{
"description": "A short description of the project"
}描述应简洁明了,一句话概括项目的用途。当项目发布到 Packagist 后,这段描述会显示在搜索结果和包详情页面。
version — 项目版本
{
"version": "1.0.0"
}version 字段
对于库/包的源码仓库,通常不需要手动设置 version 字段。Composer 会根据 Git 标签(Tag)自动推断版本号。
只有在以下场景才需要手动设置:
- 从 ZIP 归档安装(没有 Git 信息)
- 使用
composer create-project创建应用
type — 项目类型
{
"type": "project"
}| 类型 | 说明 | 示例 |
|---|---|---|
project | 应用程序项目(默认值) | Laravel 应用、网站 |
library | 可复用的库/包 | Monolog、Carbon |
composer-plugin | Composer 插件 | 安装后钩子、自定义仓库 |
metapackage | 空包,仅包含依赖关系 | Laravel 可选包集合 |
composer-installer | 自定义安装器 | Laravel 安装器 |
require — 生产依赖
{
"require": {
"php": "^8.1",
"monolog/monolog": "^2.0",
"guzzlehttp/guzzle": "^7.5",
"symfony/console": "^6.0|^7.0",
"ext-json": "*",
"ext-pdo": "*",
"ext-curl": "*"
}
}require 字段声明项目运行时必需的依赖包。即使在没有开发环境的生产服务器上,这些包也必须安装。
注意几个特殊的依赖声明:
"php": "^8.1"— 声明所需的 PHP 版本范围"ext-json": "*"— 声明所需的 PHP 扩展"ext-pdo": "*"— 声明所需的 PHP 扩展
require-dev — 开发依赖
{
"require-dev": {
"phpunit/phpunit": "^10.0",
"phpstan/phpstan": "^1.10",
"squizlabs/php_codesniffer": "^3.7",
"friendsofphp/php-cs-fixer": "^3.40",
"symfony/var-dumper": "^6.0"
}
}require-dev 字段声明仅开发时需要的依赖包,如测试框架、代码分析工具、调试工具等。生产环境部署时使用 composer install --no-dev 跳过这些依赖。
autoload — 自动加载
{
"autoload": {
"psr-4": {
"App\\": "src/",
"Domain\\": "domain/",
"Infrastructure\\": "infrastructure/"
},
"classmap": [
"src/functions.php"
],
"files": [
"src/helpers.php"
]
}
}关于自动加载的详细说明请参考 PSR-4 自动加载 一节。
autoload-dev — 开发自动加载
{
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/",
"Fixtures\\": "tests/Fixtures/"
}
}
}autoload-dev 用于声明仅开发环境需要自动加载的命名空间,如测试类、测试夹具等。生产环境不会加载这些类。
scripts — 脚本命令
{
"scripts": {
"post-install-cmd": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"test": "phpunit",
"test-coverage": "phpunit --coverage-html coverage",
"check": [
"@phpstan",
"@cs-check",
"@test"
],
"cs-check": "php-cs-fixer fix --dry-run --diff",
"cs-fix": "php-cs-fixer fix",
"phpstan": "phpstan analyse src"
}
}Composer 支持的脚本事件:
| 事件 | 触发时机 |
|---|---|
pre-install-cmd | composer install 之前 |
post-install-cmd | composer install 之后 |
pre-update-cmd | composer update 之前 |
post-update-cmd | composer update 之后 |
pre-autoload-dump | 自动加载生成之前 |
post-autoload-dump | 自动加载生成之后 |
post-create-project-cmd | composer create-project 之后 |
自定义脚本可以通过 composer run 命令执行:
composer run test
composer run phpstan
composer run checkconfig — Composer 配置
{
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"composer/installers": true,
"pestphp/pest-plugin": true
},
"platform": {
"php": "8.1.3"
},
"process-timeout": 600,
"discard-changes": true,
"github-oauth": {
"github.com": "your-github-token"
}
}
}常用配置项说明:
| 配置项 | 说明 | 默认值 |
|---|---|---|
optimize-autoloader | 是否优化自动加载(生成 classmap) | false |
preferred-install | 优先安装方式(dist/source) | auto |
sort-packages | 是否排序 require 中的包名 | false |
allow-plugins | 允许执行的 Composer 插件列表 | - |
platform | 模拟的平台版本 | 系统实际版本 |
process-timeout | 子进程超时时间(秒) | 300 |
discard-changes | 更新时是否丢弃本地修改 | false |
github-oauth | GitHub OAuth 令牌 | - |
repositories — 自定义仓库
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/my-org/my-private-repo"
},
{
"type": "composer",
"url": "https://packages.example.com"
},
{
"type": "path",
"url": "../my-local-package"
}
]
}自定义仓库顺序
自定义仓库会与 Packagist 默认仓库合并。如果自定义仓库中的包与 Packagist 中的包同名,自定义仓库优先。可以使用 packagist.org: false 禁用默认仓库:
{
"repositories": [
{
"type": "composer",
"url": "https://private-packages.example.com",
"canonical": true
},
{
"packagist.org": false
}
]
}license — 许可证
{
"license": "MIT"
}常见许可证:
MIT— 最宽松,允许几乎任何使用Apache-2.0— 类似 MIT,附带专利授权GPL-2.0/GPL-3.0— 要求衍生作品也开源BSD-2-Clause/BSD-3-Clause— 类似 MITproprietary— 专有,不允许分发
authors — 作者信息
{
"authors": [
{
"name": "张三",
"email": "zhangsan@example.com",
"homepage": "https://example.com",
"role": "Developer"
},
{
"name": "李四",
"email": "lisi@example.com",
"role": "Maintainer"
}
]
}minimum-stability — 最小稳定性
{
"minimum-stability": "stable"
}| 值 | 说明 |
|---|---|
stable | 仅接受稳定版本(默认,推荐) |
RC | 接受 Release Candidate 版本 |
beta | 接受 Beta 版本 |
alpha | 接受 Alpha 版本 |
dev | 接受开发版本(master 分支) |
minimum-stability 设置
强烈建议保持 minimum-stability 为 stable。如果你需要使用非稳定版本的包,应该通过 @ 版本约束在 require 中单独指定,而不是降低全局的最小稳定性。
{
"minimum-stability": "stable",
"require": {
"some/package": "^1.0@beta"
}
}prefer-stable — 优先稳定版
{
"prefer-stable": true
}当 minimum-stability 不是 stable 时,prefer-stable: true 会优先选择符合条件的稳定版本。这是一个很好的平衡选项。
support — 支持信息
{
"support": {
"issues": "https://github.com/vendor/project/issues",
"forum": "https://community.example.com",
"wiki": "https://github.com/vendor/project/wiki",
"source": "https://github.com/vendor/project",
"docs": "https://docs.example.com",
"rss": "https://example.com/feed.xml",
"chat": "https://discord.gg/example"
}
}keywords 和 homepage
{
"keywords": ["php", "framework", "http", "rest", "api"],
"homepage": "https://example.com"
}版本约束格式
Composer 使用丰富的版本约束语法来精确控制依赖版本:
精确版本
{
"require": {
"monolog/monolog": "1.24.0"
}
}只安装指定的精确版本。很少使用,因为过于严格。
范围版本
{
"require": {
"package-a": ">=1.0.0",
"package-b": ">=1.0.0 <2.0.0",
"package-c": ">1.0.0 <=2.3.4",
"package-d": "<=1.5.0"
}
}支持的操作符:>、>=、<、<=、!=。
波浪号 ~
{
"require": {
"package-a": "~1.2",
"package-b": "~1.2.3"
}
}~ 约束遵循 语义化版本 的下一级更新规则:
~1.2— 等价于>=1.2.0 <2.0.0(允许补丁版本更新)~1.2.3— 等价于>=1.2.3 <1.3.0(仅允许补丁版本更新)~1.2.3-beta— 等价于>=1.2.3-beta <1.3.0
脱字符 ^
{
"require": {
"package-a": "^1.2.3",
"package-b": "^0.3.0"
}
}^ 约束遵循 兼容性 更新规则:
^1.2.3— 等价于>=1.2.3 <2.0.0(兼容 1.x 的任意版本)^0.3.0— 等价于>=0.3.0 <0.4.0(对于 0.x 版本,兼容性限定更严格)^0.0.3— 等价于>=0.0.3 <0.0.4(对于 0.0.x,精确匹配)
^ 与 ~ 的选择
^— 最常用。遵循 Composer 推荐的 Semantic Versioning 2.0,允许向后兼容的更新~— 适合需要更精细控制的场景,特别是对 0.x 版本
推荐优先使用 ^,只在需要更严格控制时使用 ~。
通配符 *
{
"require": {
"package-a": "*",
"package-b": "1.*"
}
}*— 任何版本1.*— 1.x 的任何版本(等价于>=1.0.0 <2.0.0)
版本约束总结表
| 约束 | 含义 | 说明 |
|---|---|---|
1.2.3 | 精确版本 | 仅匹配 1.2.3 |
>=1.0.0 | 大于等于 | 1.0.0 及以上所有版本 |
>1.0.0 | 大于 | 1.0.1 及以上 |
>=1.0.0 <2.0.0 | 范围 | 1.x 的所有版本 |
~1.2 | 波浪号 | >=1.2.0 <2.0.0 |
~1.2.3 | 波浪号 | >=1.2.3 <1.3.0 |
^1.2.3 | 脱字符 | >=1.2.3 <2.0.0 |
^0.3.0 | 脱字符 | >=0.3.0 <0.4.0 |
1.* | 通配符 | >=1.0.0 <2.0.0 |
* | 通配符 | 任何版本 |
@stable | 稳定性 | 仅稳定版本 |
@beta | 稳定性 | Beta 及以上 |
@dev | 稳定性 | 开发版本 |
组合约束
{
"require": {
"package-a": "^1.2.3 || ^2.0",
"package-b": ">=1.0 <1.5 || >=2.0",
"package-c": "^1.0@dev"
}
}使用 || 表示"或"关系,满足任一约束即可。
完整示例
库/包的 composer.json
{
"name": "myorg/http-client",
"description": "A lightweight PHP HTTP client with PSR-7 and PSR-18 support",
"type": "library",
"license": "MIT",
"keywords": ["php", "http", "client", "psr-7", "psr-18"],
"homepage": "https://github.com/myorg/http-client",
"version": "2.1.0",
"authors": [
{
"name": "Zhang San",
"email": "zhangsan@example.com",
"role": "Lead Developer"
}
],
"require": {
"php": "^8.1",
"psr/http-message": "^1.0|^2.0",
"psr/http-factory": "^1.0",
"php-http/httplug": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"phpstan/phpstan": "^1.10",
"nyholm/psr7": "^1.5"
},
"autoload": {
"psr-4": {
"MyOrg\\HttpClient\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"MyOrg\\HttpClient\\Tests\\": "tests/"
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"config": {
"sort-packages": true,
"optimize-autoloader": true
},
"scripts": {
"test": "phpunit",
"phpstan": "phpstan analyse src --level=8",
"check": [
"@phpstan",
"@test"
]
},
"support": {
"issues": "https://github.com/myorg/http-client/issues",
"source": "https://github.com/myorg/http-client"
}
}应用程序的 composer.json
{
"name": "myorg/my-app",
"description": "My awesome web application",
"type": "project",
"license": "proprietary",
"require": {
"php": "^8.1",
"laravel/framework": "^10.0",
"laravel/tinker": "^2.8",
"guzzlehttp/guzzle": "^7.5",
"ext-pdo": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-curl": "*",
"ext-ctype": "*",
"ext-filter": "*"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"laravel/pint": "^1.10",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^7.0"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
},
"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"
],
"test": "phpunit",
"test-coverage": "phpunit --coverage-html coverage",
"pint": "vendor/bin/pint",
"pint-test": "vendor/bin/pint --test"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
}
},
"minimum-stability": "stable",
"prefer-stable": true
}实战示例:通过 PHP 读取 composer.json
<?php
declare(strict_types=1);
/**
* composer.json 读取和解析工具
*/
class ComposerJsonReader
{
public function __construct(
private readonly string $projectPath
) {}
/**
* 读取 composer.json 文件内容
*/
public function read(): array
{
$filePath = $this->projectPath . '/composer.json';
if (!file_exists($filePath)) {
throw new RuntimeException("composer.json not found: {$filePath}");
}
$content = file_get_contents($filePath);
$data = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException("Invalid JSON: " . json_last_error_msg());
}
return $data;
}
/**
* 获取项目名称
*/
public function getName(): string
{
return $this->read()['name'] ?? 'unknown';
}
/**
* 获取所有生产依赖
*/
public function getRequirements(): array
{
return $this->read()['require'] ?? [];
}
/**
* 获取所有开发依赖
*/
public function getDevRequirements(): array
{
return $this->read()['require-dev'] ?? [];
}
/**
* 检查 PHP 版本是否符合要求
*/
public function checkPhpVersion(): bool
{
$required = $this->read()['require']['php'] ?? '*';
return version_compare(PHP_VERSION, $this->extractMinVersion($required), '>=');
}
/**
* 检查所需的 PHP 扩展是否已安装
*/
public function checkExtensions(): array
{
$requirements = $this->getRequirements();
$missing = [];
foreach ($requirements as $name => $constraint) {
if (!str_starts_with($name, 'ext-')) {
continue;
}
$extension = substr($name, 4);
if (!extension_loaded($extension)) {
$missing[] = $extension;
}
}
return $missing;
}
private function extractMinVersion(string $constraint): string
{
// 简化版本提取(实际场景需要更完整的语义化版本解析)
preg_match('/(\d+\.\d+\.\d+)/', $constraint, $matches);
return $matches[1] ?? '0.0.0';
}
}
// 使用示例
$reader = new ComposerJsonReader('/var/www/html');
echo "项目: " . $reader->getName() . "\n";
echo "PHP 版本: " . PHP_VERSION . "\n";
echo "依赖检查: " . ($reader->checkPhpVersion() ? '通过' : '不通过') . "\n";
$missing = $reader->checkExtensions();
if (!empty($missing)) {
echo "缺少扩展: " . implode(', ', $missing) . "\n";
}注意事项
1. composer.json 与 composer.lock 的关系
composer.json — 声明版本范围(如 "^2.0")
composer.lock — 锁定精确版本(如 "2.3.1")
团队协作流程:
1. 开发者 A 运行 composer update → 更新 composer.lock
2. 提交 composer.json 和 composer.lock
3. 开发者 B 运行 composer install → 按 composer.lock 安装精确版本
4. 部署到生产 → composer install --no-dev → 安装生产依赖2. 不要手动编辑 composer.lock
# composer.lock 由 Composer 自动管理
# 不要手动编辑,除非你完全理解其中的影响
# 正确的更新方式:
composer update # 更新所有依赖
composer update monolog/* # 仅更新 monolog
composer update --lock # 重新生成 lock 文件(不安装)3. 版本冲突排查
# 当依赖冲突时,查看依赖树
composer show monolog/monolog
composer why monolog/monolog # 查看谁依赖了 monolog
composer why-not php 8.2 # 查看为什么不能升级到 PHP 8.2最佳实践
1. 始终提交 composer.lock
# 应用程序项目:必须提交 composer.lock
git add composer.json composer.lock
git commit -m "Update dependencies"
# 库/包项目:通常不提交 composer.lock
# 因为库的使用者不应该受包作者本地依赖版本的影响2. 使用 composer validate 检查
# 提交前验证 composer.json 的语法和有效性
composer validate
# 严格验证(检查仓库可用性等)
composer validate --strict3. 使用 normalize 格式化
# 安装 normalize 插件
composer require --dev ergebnis/composer-normalize
# 格式化 composer.json
composer normalize
# 它会帮你:
# - 排序所有字段
# - 排序 require 中的包名
# - 统一引号风格
# - 移除多余空行下一节
你已经了解了 composer.json 的完整结构和版本约束格式,接下来将学习 Composer 的基本命令,掌握依赖安装、更新、搜索等常用操作。