Skip to content

▶️ 执行厂商二进制文件

执行 Composer 安装到 vendor/bin 下的工具(PHPUnit、PHPStan、Psalm 等),并提供列出、批量执行、指定 PHP 解释器与工作目录等能力。

composer exec 会自动把 vendor/bin 加入 PATH,避免你手写 ./vendor/bin/phpunit 这种长路径。Composer Skills 在此基础上加了 ExecAll(批量执行所有二进制)和 ExecCommand(通用命令执行)两个便捷封装。

何时使用

  • 🧪 在 Go 编排的工具链里调用 PHPUnit / PHPStan 等厂商工具,不想关心 vendor/bin 路径。
  • 🐘 需要用特定 PHP 版本运行某个工具(多版本测试矩阵)。
  • 📂 在与默认工作目录不同的子项目里执行工具。
  • 🚀 一次性运行所有厂商二进制(如批量自检脚本)。

方法签名

方法签名说明
▶️ Execfunc (c *Composer) Exec(binary string, args ...string) (string, error)执行厂商二进制(exec binary -- args
📋 ExecWithListfunc (c *Composer) ExecWithList() ([]string, error)列出所有可用厂商二进制
🐘 ExecPHPfunc (c *Composer) ExecPHP(php string, binary string, args ...string) (string, error)用指定 PHP 解释器执行
📂 ExecWithWorkingDirfunc (c *Composer) ExecWithWorkingDir(binary string, workingDir string, args ...string) (string, error)在指定工作目录执行
🚀 ExecAllfunc (c *Composer) ExecAll(args ...string) (map[string]string, error)对所有厂商二进制批量执行
💻 ExecCommandfunc (c *Composer) ExecCommand(command string, args ...string) (string, error)通用命令执行(composer command args

参数说明

Exec / ExecPHP

参数类型说明
binarystring厂商二进制名,如 phpunit
args...string透传给二进制的参数

ExecPHP

参数类型说明
phpstringPHP 可执行文件路径,如 /usr/bin/php8.2

ExecWithWorkingDir

参数类型说明
workingDirstring临时切换到的工作目录(执行后自动恢复)

示例

运行 PHPUnit

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.Fatalf("初始化失败: %v", err)
	}

	out, err := comp.Exec("phpunit", "--testsuite=unit", "--stop-on-failure")
	if err != nil {
		log.Fatalf("PHPUnit 失败: %v\n%s", err, out)
	}
	fmt.Println(out)
}

用指定 PHP 版本运行 PHPStan

go
out, err := comp.ExecPHP("/usr/bin/php8.3", "phpstan", "analyse", "src", "--level=8")
if err != nil {
	log.Fatalf("PHPStan 失败: %v\n%s", err, out)
}
fmt.Println(out)

在子目录执行

go
// workingDir 在函数返回后自动恢复原值
out, err := comp.ExecWithWorkingDir("phpunit", "/path/to/subproject", "--testdox")
if err != nil {
	log.Fatal(err)
}
fmt.Println(out)

列出可用二进制

go
bins, err := comp.ExecWithList()
if err != nil {
	log.Fatal(err)
}
for _, b := range bins {
	fmt.Println("🧰", b)
}

批量执行所有二进制

go
// 把 --version 透传给每个厂商二进制
results, err := comp.ExecAll("--version")
if err != nil {
	log.Fatal(err)
}
for bin, out := range results {
	fmt.Printf("=== %s ===\n%s\n", bin, out)
}

通用命令执行

go
// 直接执行 composer 的某个子命令
out, err := comp.ExecCommand("show", "--self")
if err != nil {
	log.Fatal(err)
}
fmt.Println(out)

进阶

Exec 的参数分隔

Execbinaryargs 之间插入 --,确保后续参数不被 composer exec 自己解析。例如 Exec("phpunit", "--filter=testFoo") 实际执行 composer exec phpunit -- --filter=testFoo

ExecAll 的错误隔离

ExecAll 内部对每个二进制单独调用 Exec,单个失败不会中断整体流程——失败的工具输出会被替换为 "Error: <err>" 写入结果 map。返回的 error 仅在 ExecWithList 失败时非 nil。

ExecWithWorkingDir 非线程安全

该方法通过临时修改 c.workingDirdefer 恢复实现。不要在多个 goroutine 共用同一个 *Composer 实例时调用它,否则工作目录会被互相覆盖。

基于 MIT 许可证发布