本文目录导读:

梳理并精简PHP项目的依赖,通常分为两个大方向:自动检测(利用工具)和 手动分析(理解业务与框架)。
下面是一套比较完整的梳理与精简方案,分为分析现状、精简操作、持续管控三个阶段。
第一阶段:全面分析与诊断
在删除任何依赖之前,必须知道哪些是真正用到的,哪些是“幽灵依赖”。
使用 Composer 自带分析工具
# 1. 查看为什么某个包被安装(依赖树分析) composer why package/name # 2. 反向查看某个包被哪些项目依赖 composer why-not package/name # 3. 生成完整的依赖关系图(文本版) composer depends --tree package/name # 4. 检查是否存在可更新的版本(兼容当前约束) composer outdated --direct # 只看直接依赖 composer outdated --major # 看大版本升级
静态代码分析工具(推荐)
这是最精准的方法,扫描代码中实际被 use 或 require 的包。
工具推荐: maglnet/composer-require-checker
# 安装 composer require --dev maglnet/composer-require-checker # 运行分析 ./vendor/bin/composer-require-checker check
它会输出:
- Missing packages:代码中用了但
composer.json没声明(这是问题) - Unused packages:
composer.json声明了但代码中没直接调用(这是可精简目标)
注意: 该工具只能检测直接依赖,间接依赖(A依赖B,B依赖C)如果C在代码中显式被 use,也会被标记为未声明。
检查 require-dev / require 分类
很多包不应该出现在生产环境的 require 中。
| 包类型 | 应归属 | 理由 |
|---|---|---|
| PHPUnit, PHPStan, PHPCS | require-dev |
仅开发/CI用 |
| Faker, Mockery | require-dev |
仅测试用 |
| Laravel Debugbar, Telescope | require-dev |
仅开发环境 |
| Laravel Horizon, Redis 驱动 | require |
生产环境需要 |
| 代码生成器(如 ide-helper) | require-dev |
仅开发时运行 |
快速检查命令:
# 查看哪些 dev 包被错误放入 require composer show --self
分析框架自带的功能
许多框架已经内置了常见功能,无需额外包。
- Laravel:自带 Guzzle,无需额外装 HTTP 客户端;自带验证规则,不需要额外验证库;自带邮箱发送,不需要
swiftmailer(新版 laravel 已经内置 symfony mailer) - Symfony:大量 Bundle 可能包含不需要的子依赖
- ThinkPHP / Yii:检查是否有更精简的替代实现
第二阶段:执行精简操作
移除未使用的直接依赖
根据分析结果,对每个疑似无用包:
# 先模拟移除 composer remove package/name --dry-run # 确认无误后实际移除 composer remove package/name # 清理整个 vendor 和锁文件 rm -rf vendor composer.lock composer install
替代臃肿的包(常见案例)
| 臃肿包 | 替代方案 | 节省空间 |
|---|---|---|
guzzlehttp/guzzle |
symfony/http-client 或 php-curl-class |
减少 2-3 个间接路由包 |
monolog/monolog |
直接使用 Psr\Log\LoggerInterface + error_log() |
如果业务简单,可省掉整个 monolog 体系 |
doctrine/dbal |
PDO + 原生 SQL | 对于非复杂查询,可精简几十个依赖 |
laravel/framework |
拆分为 illuminate/* 单独组 |
只取需要的组件 |
intervention/image |
spatie/image 或直接 GD/Imagick |
体积更小,依赖更少 |
spatie/laravel-permission |
自己写 2 个关系表 + 中间件 | 省掉一个完整权限包的 10+ 依赖 |
合并功能相似的包
- ✅
league/flysystem+league/flysystem-aws-s3-v3可以合并配置 - ✅ 多个
spatie/*包如果只用了其中一小部分功能,考虑手动实现 - ❌ 不要同时装
guzzlehttp/guzzle+symfony/http-client+php-curl处理同一类事情
移除 composer.json 中的无用约束
{
"require": {
"php": ">=7.4 || >=8.0" // 可以压缩为 ">=7.4"
}
}
第三阶段:持续管控与监控
建立 CI 检查流水线
在 .github/workflows/ci.yml 或 .gitlab-ci.yml 中添加:
- name: 检查未使用的依赖
run: |
composer require --dev maglnet/composer-require-checker
vendor/bin/composer-require-checker check
定期运行依赖审计
# 检查已知安全漏洞 composer audit # 检查是否有更新的替代包 composer suggest --all
锁定版本策略
避免使用 ^1.0 这种宽松约束导致意外引入新包:
{
"require": {
"vendor/package": "1.2.*" // 只允许小版本更新
}
}
使用 prefer-lowest 做兼容性测试
composer update --prefer-lowest
这能帮你发现哪些包实际上限制了更旧但可以工作的版本。
典型案例:Laravel 项目依赖精简
假设一个标准的 Laravel 8/9/10 项目,composer.json 往往有 20~30 个包,精简后可能降到 10~15 个。
可移除项:
| 包名 | 移除理由 |
|---|---|
facade/ignition |
Laravel 10+ 已用 flare 替代,早期版本可直接删 |
nunomaduro/collision |
终端输出美化,不影响运行 |
laravel/sail |
Docker 环境,不需要在生产 require 中 |
barryvdh/laravel-ide-helper |
仅开发环境 |
laravel/tinker |
如果不在生产环境 php artisan tinker,可移入 dev |
laravel/sanctum |
如果不用 API token 认证,可移除 |
laravel/horizon |
如果不用 Redis 队列管理,可移除 |
最终精简后示例:
{
"require": {
"php": "^8.1",
"laravel/framework": "^10.0"
// 仅保留业务必须的业务包
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"nunomaduro/collision": "^7.0",
"spatie/laravel-ignition": "^1.0"
}
}
最后建议
- 不要追求极致精简:省掉一个包往往意味着自己维护代码,带来的维护成本可能更高
- 优先移除
require-dev中的误放包:这直接影响生产环境 docker 镜像体积 - 利用
composer why反向溯源:当你发现一个看似无用的包时,先查它被谁依赖 - 保留 composer.lock:精简后重新生成锁文件,确保环境一致性