📦 从 Go 管理 PHP 依赖
12 分钟,用 Composer CLI SDK 替代手写 exec.Command 完成 Install / Require / Update / Remove,并拿到结构化的依赖树和过期信息。需要本机已安装 PHP 7.4+ 与 Composer 2.0+。
为什么不用 exec.Command
裸调 composer 二进制要自己拼参数、解析多行文本、处理退出码。Composer CLI SDK 把这些封装成类型化方法,返回 error 或结构体,测试时还能注入 Mock。
第 1 步:创建 Composer 实例
composer.New(composer.DefaultOptions()) 会自动检测本机 Composer;默认开启 AutoInstall,找不到时会自动安装。
go
comp, err := composer.New(composer.DefaultOptions())
if err != nil {
log.Fatal(err)
}
comp.SetWorkingDir("/path/to/php/project") // 指向含 composer.json 的目录第 2 步:安装现有依赖
Install(noDev, optimize) 对应 composer install。第一个参数控制是否排除 dev 依赖,第二个控制是否优化自动加载。
第 3 步:增/删/升级
RequirePackage(name, version, dev)— 添加依赖并写入 composer.json。Update(packages, noDev)— 升级指定包(空切片表示全量)。Remove(name, dev)— 移除依赖。
第 4 步:拿结构化结果
ShowDependencyTree(name)— 返回某包的依赖树文本。GetOutdatedInfo()— 返回*OutdatedResult,含每个过期包的当前版本、最新版本、升级类型。
完整可运行示例
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func main() {
comp, err := composer.New(composer.DefaultOptions())
if err != nil {
log.Fatal(err)
}
comp.SetWorkingDir("/tmp/my-php-project")
// 1️⃣ 安装 composer.lock 里的依赖(不含 dev,优化自动加载)
if err := comp.Install(false, true); err != nil {
log.Printf("install: %v", err)
}
// 2️⃣ 添加 monolog ^3.0
if err := comp.RequirePackage("monolog/monolog", "^3.0", false); err != nil {
log.Fatalf("require: %v", err)
}
// 3️⃣ 升级 monolog(传空切片表示只更新列出的包)
if err := comp.Update([]string{"monolog/monolog"}, false); err != nil {
log.Printf("update: %v", err)
}
// 4️⃣ 看依赖树
tree, err := comp.ShowDependencyTree("monolog/monolog")
if err != nil {
log.Printf("tree: %v", err)
} else {
fmt.Println("🌳 依赖树:")
fmt.Println(tree)
}
// 5️⃣ 结构化的过期包列表
outdated, err := comp.GetOutdatedInfo()
if err != nil {
log.Printf("outdated: %v", err)
} else {
fmt.Printf("⏳ 过期包数量: %d\n", len(outdated.Installed))
for _, p := range outdated.Installed {
fmt.Printf(" - %s: %s → %s (%s)\n",
p.Name, p.Installed, p.Latest, p.LatestStatus)
}
}
// 6️⃣ 移除 monolog
if err := comp.Remove("monolog/monolog", false); err != nil {
log.Printf("remove: %v", err)
}
}预期输出
🌳 依赖树:
monolog/monolog 3.5.0
├── psr/log 3.0.0
└── ...
⏳ 过期包数量: 2
- monolog/monolog: 3.5.0 → 3.7.1 (semver-safe-update)
- psr/log: 3.0.0 → 3.0.2 (semver-safe-update)进阶:WithOptions 与多包操作
需要传额外 CLI 参数时用 *WithOptions 变体:
go
// 安装时指定 prefer-dist 并跳过脚本
comp.InstallWithOptions(map[string]string{
"prefer-dist": "",
"no-scripts": "",
})
// 一次性 require 多个包
comp.RequireMultiple(map[string]string{
"monolog/monolog": "^3.0",
"symfony/console": "^7.0",
}, false)先试运行再真改
InstallDryRun()、UpdateDryRun(packages)、RequireDryRun(name, version) 只打印不落盘,适合在 CI 里预演。
工作目录很关键
忘记 SetWorkingDir 会在当前 Go 进程目录执行 composer,多半会报 "composer.json not found"。务必指向真实的 PHP 项目根目录。
下一步
- 想把过期/许可证/资金汇总成一张表?看 📈 依赖仪表盘。
- 想在 CI 里自动安装 Composer?看 🤖 CI/CD 中自动检测与安装。