依赖管理策略
Composer 是 PHP 生态的标准依赖管理工具,它自动处理包的安装、更新和自动加载。合理的依赖管理策略能够确保项目稳定性、安全性和可维护性。本节将深入讲解 Composer 版本锁定、私有仓库、平台要求以及生产与开发依赖的划分策略。
基础概念
Composer 的核心文件
| 文件 | 作用 | 是否提交到 Git |
|---|---|---|
composer.json | 项目依赖声明 | 是 |
composer.lock | 依赖版本锁定 | 是 |
vendor/ | 已安装的包 | 否 |
composer.phar | Composer 可执行文件 | 否 |
Composer 版本约束
版本约束格式
json
{
"require": {
"php": "^8.1",
"monolog/monolog": "^2.0",
"guzzlehttp/guzzle": "^7.5",
"symfony/console": "~6.0",
"doctrine/orm": ">=3.0",
"laravel/framework": ">=10.0 <11.0",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*"
}
}版本约束详解
text
精确版本: "1.2.3" 仅匹配 1.2.3
范围版本: ">=1.0 <2.0" 匹配 1.0 到 2.0 之间(不含 2.0)
波浪号: "~1.2" 匹配 >=1.2 <2.0(次版本锁定)
波浪号: "~1.2.3" 匹配 >=1.2.3 <1.3.0(补丁版本锁定)
脱字符: "^1.2.3" 匹配 >=1.2.3 <2.0.0(语义化版本兼容)
星号: "*" 任意版本(不推荐)json
{
"require": {
"psr/log": "^1.1", // 1.1.x ~ 1.x.x(< 2.0)
"symfony/console": "^6.0", // 6.0.x ~ 6.x.x(< 7.0)
"guzzlehttp/guzzle": "~7.5", // 7.5.x ~ 7.x.x(< 8.0)
"phpunit/phpunit": ">=10.0 <11.0", // 精确范围
"my/package": "dev-main", // 开发分支
"my/package": "dev-main#abc1234" // 特定 commit
}
}stability 配置
json
{
"minimum-stability": "stable",
"prefer-stable": true,
"repositories": [
{
"type": "vcs",
"url": "https://github.com/my/private-repo"
}
]
}composer.json 完整配置
项目模板配置
json
{
"name": "my-company/my-project",
"description": "My awesome PHP project",
"version": "1.0.0",
"type": "project",
"keywords": ["php", "web", "api"],
"license": "MIT",
"authors": [
{
"name": "Developer Name",
"email": "dev@example.com"
}
],
"support": {
"email": "support@example.com",
"issues": "https://github.com/my-company/my-project/issues"
},
"require": {
"php": "^8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pdo": "*",
"guzzlehttp/guzzle": "^7.5",
"monolog/monolog": "^2.0|^3.0",
"nesbot/carbon": "^2.62",
"ramsey/uuid": "^4.5",
"symfony/console": "^6.0",
"symfony/dotenv": "^6.0",
"symfony/yaml": "^6.0",
"vlucas/phpdotenv": "^5.4"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.15",
"nunomaduro/larastan": "^2.0",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-symfony": "^1.10",
"phpunit/phpunit": "^10.0",
"squizlabs/php_codesniffer": "^3.7",
"symfony/phpunit-bridge": "^6.0"
},
"autoload": {
"psr-4": {
"App\\": "src/"
},
"psr-0": {
"Legacy_": "src/Legacy/"
},
"classmap": [
"src/functions.php"
],
"files": [
"src/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"autoload-suggestions": {
"ext-pcntl": "For better signal handling in long-running processes",
"ext-posix": "For process control functions"
},
"scripts": {
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
],
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install --symlink --relative": "symfony-cmd"
},
"test": "phpunit",
"test:coverage": "phpunit --coverage-html coverage/",
"phpstan": "phpstan analyse src/ --level=8",
"cs-check": "php-cs-fixer fix --dry-run --diff",
"cs-fix": "php-cs-fixer fix",
"check": [
"@cs-check",
"@phpstan",
"@test"
]
},
"scripts-descriptions": {
"test": "Run unit tests",
"phpstan": "Run PHPStan static analysis",
"cs-check": "Check coding style",
"cs-fix": "Fix coding style issues",
"check": "Run all quality checks"
},
"config": {
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true,
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true
},
"platform": {
"php": "8.1.0"
},
"platform-check": true
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "6.0.*"
},
"branch-alias": {
"dev-main": "1.0.x-dev"
}
},
"bin": [
"bin/my-app"
],
"archive": {
"exclude": ["/tests", "/.github", "/docs"]
}
}私有仓库配置
Satis 自建仓库
bash
# 安装 Satis
composer create-project composer/satis --stability=dev satis-repo
# satis.json 配置
cat > satis-repo/satis.json << 'EOF'
{
"name": "My Company Packages",
"homepage": "https://packages.example.com",
"repositories": [
{ "type": "vcs", "url": "https://github.com/my-company/package-core" },
{ "type": "vcs", "url": "https://github.com/my-company/package-http" },
{ "type": "vcs", "url": "https://github.com/my-company/package-db" }
],
"require-all": true,
"archive": {
"directory": "dist",
"format": "tar",
"prefix-url": "https://packages.example.com/dist",
"skip-dev": true
}
}
EOF
# 构建
php satis-repo/bin/satis build satis-repo/satis.json satis-repo/web/使用私有仓库
json
{
"repositories": [
{
"type": "composer",
"url": "https://packages.example.com"
},
{
"type": "vcs",
"url": "https://github.com/my-company/private-package"
},
{
"type": "svn",
"url": "https://svn.example.com/my-package/trunk"
}
]
}认证配置
bash
# ~/.composer/auth.json
{
"github-oauth": {
"github.com": "ghp_xxxxxxxxxxxx"
},
"http-basic": {
"packages.example.com": {
"username": "deploy-token",
"password": "token-value"
},
"repo.example.com": {
"username": "git",
"password": "personal-access-token"
}
},
"bearer": {
"packages.example.com": "api-token"
}
}不要将认证信息提交到 Git
auth.json 应放在 ~/.composer/ 目录中,而非项目目录。CI 环境使用环境变量或 secret 管理认证。
平台要求
PHP 版本管理
json
{
"require": {
"php": "^8.1"
},
"config": {
"platform": {
"php": "8.1.20"
},
"platform-check": true
}
}PHP 扩展要求
json
{
"require": {
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-filter": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pdo": "*",
"ext-session": "*",
"ext-simplexml": "*",
"ext-soap": "*",
"ext-sodium": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"ext-zlib": "*"
}
}扩展版本约束
某些扩展支持版本约束,如 "ext-simplexml": "^0.1"。大多数情况下使用 "*" 即可。
生产依赖 vs 开发依赖
依赖分类原则
json
{
"require": {
"guzzlehttp/guzzle": "^7.5",
"monolog/monolog": "^2.0",
"symfony/console": "^6.0",
"nesbot/carbon": "^2.62"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"phpstan/phpstan": "^1.10",
"friendsofphp/php-cs-fixer": "^3.15",
"squizlabs/php_codesniffer": "^3.7",
"symfony/var-dumper": "^6.0",
"fakerphp/faker": "^1.20",
"brianium/paratest": "^7.0"
}
}安装与部署
bash
# 开发环境:安装所有依赖(含 dev)
composer install
# 生产环境:仅安装生产依赖
composer install --no-dev --optimize-autoloader --no-interaction --no-progress
# 使用 classmap 优化自动加载(更快)
composer dump-autoload --optimize --classmap-authoritative --no-dev
# 生产环境检查平台要求
composer check-platform-reqsComposer 脚本
实用脚本配置
json
{
"scripts": {
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate"
],
"post-install-cmd": [
"App\\Console\\ComposerScripts::postInstall"
],
"post-update-cmd": [
"App\\Console\\ComposerScripts::postUpdate"
],
"dev": [
"Composer\\Config::disableProcessTimeout",
"@composer install --prefer-dist"
],
"fresh": [
"@composer install --prefer-dist",
"@php artisan key:generate",
"@php artisan migrate:fresh --seed"
],
"test": "phpunit",
"test:unit": "phpunit --testsuite=Unit",
"test:feature": "phpunit --testsuite=Feature",
"test:parallel": "paratest --processes=4",
"phpstan": "phpstan analyse --memory-limit=512M",
"phpstan:baseline": "phpstan analyse --generate-baseline=phpstan-baseline.neon",
"cs:check": "php-cs-fixer fix --dry-run --diff --using-cache=no",
"cs:fix": "php-cs-fixer fix --using-cache=no",
"quality": [
"@cs:check",
"@phpstan",
"@test"
]
}
}Composer 常用命令
bash
# 安装依赖
composer install # 根据 lock 文件安装
composer update # 更新所有依赖
composer update package/name # 更新特定包
composer update --prefer-dist # 优先下载 dist 包
composer update --with-all-dependencies # 更新及其依赖
# 添加依赖
composer require vendor/package # 添加到 require
composer require --dev vendor/package # 添加到 require-dev
# 移除依赖
composer remove vendor/package # 从 require 移除
composer remove --dev vendor/package # 从 require-dev 移除
# 诊断
composer diagnose # 诊断 Composer 问题
composer show # 显示已安装包信息
composer show vendor/package --tree # 显示包的依赖树
composer depends vendor/package # 查看谁依赖了这个包
composer why vendor/package # 同上
composer outdated # 列出可更新的包
composer licenses # 显示许可证信息
# 自动加载
composer dump-autoload # 重新生成自动加载
composer dump-autoload -o # 优化自动加载
composer dump-autoload -a # classmap 权威模式(生产推荐)
# 其他
composer validate # 验证 composer.json
composer run-script test # 运行自定义脚本
composer global require phpunit/phpunit # 全局安装实战示例
多环境 composer.json 管理
bash
# 开发环境使用 .env.local 中的 PHP 版本
# CI 环境通过 platform-check 确保平台兼容
# 检查平台要求
composer check-platform-reqs
# 输出示例:
# php 8.1.20 success
# ext-curl 7.68.0 success
# ext-json 8.1.20 success
# ext-mbstring on success注意事项
常见问题
必须提交 composer.lock
composer.lock 必须提交到版本控制。忽略 lock 文件会导致团队成员安装不同版本的依赖,造成不一致行为。
composer.lock必须提交到 Git,确保所有环境使用相同的依赖版本- 生产环境使用
--no-dev跳过开发依赖 - 定期运行
composer outdated检查安全更新 - 使用
prefer-dist加快安装速度(下载 zip 而非克隆 Git) - 依赖版本约束不要太宽松(避免
*),也不要太严格(避免精确版本)
最佳实践
- 锁定版本:始终提交
composer.lock,生产环境使用composer install - 区分依赖:生产依赖和开发依赖严格分开
- 平台检查:配置
platform-check确保环境兼容 - 优化加载:生产环境使用
--optimize-autoloader --classmap-authoritative - 定期更新:每月检查依赖更新和安全补丁
- 最小化依赖:仅添加真正需要的包,减少攻击面
下一节
继续学习:PHP-FPM 调优