Skip to content

composer.json 配置

composer.json 是 Composer 项目的核心配置文件,它定义了项目的元数据、依赖关系、自动加载规则和脚本命令。每一个使用 Composer 管理的 PHP 项目都必须包含这个文件。本节将深入详解 composer.json 的每个字段、版本约束格式、最小稳定性设置,并通过完整的示例展示如何编写规范的配置文件。

前置知识

在阅读本节之前,你需要了解:

  • Composer 已安装(参见 Composer 安装
  • JSON 文件格式基础
  • PHP 命名空间的概念
  • 语义化版本号(Semantic Versioning)基本概念

composer.json 概述

composer.json 位于项目根目录,是 Composer 的入口配置文件。它告诉 Composer:

  • 这个项目叫什么
  • 项目需要哪些依赖包及其版本
  • 如何自动加载 PHP 类
  • 需要执行哪些脚本命令
  • 使用哪些仓库源

你可以通过 composer init 命令交互式地创建 composer.json,也可以手动创建。

核心字段详解

name — 项目名称

json
{
    "name": "vendor/project"
}

项目名称由 vendor(供应商/组织)和 project(项目名)两部分组成,用 / 分隔。

  • vendor — 通常是公司名或开发者名(如 laravelsymfonymonolog
  • project — 项目或包的名称(如 frameworkconsolemonolog

何时需要 name 字段

  • 库/包(被其他项目引用)— 必须设置 name
  • 应用程序/项目(不被其他项目引用)— name 是可选的,但建议设置

名称一旦发布到 Packagist,就不应该再更改,因为其他项目可能已经依赖了这个名称。

description — 项目描述

json
{
    "description": "A short description of the project"
}

描述应简洁明了,一句话概括项目的用途。当项目发布到 Packagist 后,这段描述会显示在搜索结果和包详情页面。

version — 项目版本

json
{
    "version": "1.0.0"
}

version 字段

对于库/包的源码仓库,通常不需要手动设置 version 字段。Composer 会根据 Git 标签(Tag)自动推断版本号。

只有在以下场景才需要手动设置:

  • 从 ZIP 归档安装(没有 Git 信息)
  • 使用 composer create-project 创建应用

type — 项目类型

json
{
    "type": "project"
}
类型说明示例
project应用程序项目(默认值)Laravel 应用、网站
library可复用的库/包Monolog、Carbon
composer-pluginComposer 插件安装后钩子、自定义仓库
metapackage空包,仅包含依赖关系Laravel 可选包集合
composer-installer自定义安装器Laravel 安装器

require — 生产依赖

json
{
    "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 — 开发依赖

json
{
    "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 — 自动加载

json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "Domain\\": "domain/",
            "Infrastructure\\": "infrastructure/"
        },
        "classmap": [
            "src/functions.php"
        ],
        "files": [
            "src/helpers.php"
        ]
    }
}

关于自动加载的详细说明请参考 PSR-4 自动加载 一节。

autoload-dev — 开发自动加载

json
{
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/",
            "Fixtures\\": "tests/Fixtures/"
        }
    }
}

autoload-dev 用于声明仅开发环境需要自动加载的命名空间,如测试类、测试夹具等。生产环境不会加载这些类。

scripts — 脚本命令

json
{
    "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-cmdcomposer install 之前
post-install-cmdcomposer install 之后
pre-update-cmdcomposer update 之前
post-update-cmdcomposer update 之后
pre-autoload-dump自动加载生成之前
post-autoload-dump自动加载生成之后
post-create-project-cmdcomposer create-project 之后

自定义脚本可以通过 composer run 命令执行:

bash
composer run test
composer run phpstan
composer run check

config — Composer 配置

json
{
    "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-oauthGitHub OAuth 令牌-

repositories — 自定义仓库

json
{
    "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 禁用默认仓库:

json
{
    "repositories": [
        {
            "type": "composer",
            "url": "https://private-packages.example.com",
            "canonical": true
        },
        {
            "packagist.org": false
        }
    ]
}

license — 许可证

json
{
    "license": "MIT"
}

常见许可证:

  • MIT — 最宽松,允许几乎任何使用
  • Apache-2.0 — 类似 MIT,附带专利授权
  • GPL-2.0 / GPL-3.0 — 要求衍生作品也开源
  • BSD-2-Clause / BSD-3-Clause — 类似 MIT
  • proprietary — 专有,不允许分发

authors — 作者信息

json
{
    "authors": [
        {
            "name": "张三",
            "email": "zhangsan@example.com",
            "homepage": "https://example.com",
            "role": "Developer"
        },
        {
            "name": "李四",
            "email": "lisi@example.com",
            "role": "Maintainer"
        }
    ]
}

minimum-stability — 最小稳定性

json
{
    "minimum-stability": "stable"
}
说明
stable仅接受稳定版本(默认,推荐)
RC接受 Release Candidate 版本
beta接受 Beta 版本
alpha接受 Alpha 版本
dev接受开发版本(master 分支)

minimum-stability 设置

强烈建议保持 minimum-stabilitystable。如果你需要使用非稳定版本的包,应该通过 @ 版本约束在 require 中单独指定,而不是降低全局的最小稳定性。

json
{
    "minimum-stability": "stable",
    "require": {
        "some/package": "^1.0@beta"
    }
}

prefer-stable — 优先稳定版

json
{
    "prefer-stable": true
}

minimum-stability 不是 stable 时,prefer-stable: true 会优先选择符合条件的稳定版本。这是一个很好的平衡选项。

support — 支持信息

json
{
    "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

json
{
    "keywords": ["php", "framework", "http", "rest", "api"],
    "homepage": "https://example.com"
}

版本约束格式

Composer 使用丰富的版本约束语法来精确控制依赖版本:

精确版本

json
{
    "require": {
        "monolog/monolog": "1.24.0"
    }
}

只安装指定的精确版本。很少使用,因为过于严格。

范围版本

json
{
    "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"
    }
}

支持的操作符:>>=<<=!=

波浪号 ~

json
{
    "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

脱字符 ^

json
{
    "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 版本

推荐优先使用 ^,只在需要更严格控制时使用 ~

通配符 *

json
{
    "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稳定性开发版本

组合约束

json
{
    "require": {
        "package-a": "^1.2.3 || ^2.0",
        "package-b": ">=1.0 <1.5 || >=2.0",
        "package-c": "^1.0@dev"
    }
}

使用 || 表示"或"关系,满足任一约束即可。

完整示例

库/包的 composer.json

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

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
<?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

bash
# composer.lock 由 Composer 自动管理
# 不要手动编辑,除非你完全理解其中的影响

# 正确的更新方式:
composer update              # 更新所有依赖
composer update monolog/*   # 仅更新 monolog
composer update --lock       # 重新生成 lock 文件(不安装)

3. 版本冲突排查

bash
# 当依赖冲突时,查看依赖树
composer show monolog/monolog
composer why monolog/monolog  # 查看谁依赖了 monolog
composer why-not php 8.2      # 查看为什么不能升级到 PHP 8.2

最佳实践

1. 始终提交 composer.lock

bash
# 应用程序项目:必须提交 composer.lock
git add composer.json composer.lock
git commit -m "Update dependencies"

# 库/包项目:通常不提交 composer.lock
# 因为库的使用者不应该受包作者本地依赖版本的影响

2. 使用 composer validate 检查

bash
# 提交前验证 composer.json 的语法和有效性
composer validate

# 严格验证(检查仓库可用性等)
composer validate --strict

3. 使用 normalize 格式化

bash
# 安装 normalize 插件
composer require --dev ergebnis/composer-normalize

# 格式化 composer.json
composer normalize

# 它会帮你:
# - 排序所有字段
# - 排序 require 中的包名
# - 统一引号风格
# - 移除多余空行

下一节

你已经了解了 composer.json 的完整结构和版本约束格式,接下来将学习 Composer 的基本命令,掌握依赖安装、更新、搜索等常用操作。

参考链接