编程

CPX: 用于 PHP 的 Composer 包执行器

4 2026-10-02 15:32:00

cpx CLI 从任何 Composer 软件包运行命令,而无需在项目中安装该软件包 — cpx 之于 Composer 就像 npx 之于 npm。

如果您曾经使用 Composer Global require 安装了一个工具,然后与全局安装的其他工具发生依赖项冲突,cpx 会通过隔离的依赖项消除该冲突。

它将每个包安装到自己的目录中,与项目的依赖项和全局 Composer 设置分开,然后从那里运行命令。重复运行同一版本可重复使用该安装,并且 cpx 会随时检查更新。

运行您尚未安装的软件包

传递包名称,后跟命令及其参数。这里的包名称是您在composer.json中放置的任何名称,并且支持版本约束:

cpx friendsofphp/php-cs-fixer php-cs-fixer fix ./src
cpx friendsofphp/php-cs-fixer:^3.0 php-cs-fixer fix ./src

当软件包只包含单个二进制文件,或者该二进制文件的名称与软件包名称相同时,您可以省略命令名称:

cpx friendsofphp/php-cs-fixer fix ./src

如果一个包包含多个二进制文件且你未指定具体名称,cpx 2.0 会提示你进行选择。

你也可以将 cpx 指向一个目录而非包名,这在本地开发包时非常有用:

cpx ../my-package --version

该目录必须包含有效的 composer.json,且其依赖项已安装至 vendor/autoload.php。cpx 会直接从该检出目录运行声明的二进制文件,而不会对其进行复制、缓存或进行其他形式的管理。

默认优先使用本地二进制文件

如果你曾使用过 1.x 版本,这一点是最值得注意的行为变更。cpx 现在会先在你的项目中查找二进制文件,而不是直接安装一个独立副本。它会从当前目录向上逐级查找最近的 Composer 项目,并运行该项目 `bin-dir` 配置中对应的二进制文件:

cpx pint                 # runs vendor/bin/pint when the project has it
cpx phpunit --filter=Foo # runs vendor/bin/phpunit when present
cpx laravel/pint:^2.0    # uses the local pint only if it satisfies ^2.0

因此,在项目内部,`cpx` 会运行项目中指定的版本,而不是最新的版本。如果没有匹配的本地二进制文件,`cpx` 会回退到安装并运行一个独立副本。若要强制使用独立副本,请在包名称前加上 --skip-local 参数。

别名现可由您自行定义

1.x 版本内置了一份针对常用包的快捷命令列表,因此 cpx phpstan 和 cpx laravel 等命令开箱即用。该列表在 2.0 版本中已被移除,现在您可以自行定义别名:

cpx alias phpstan/phpstan phpstan
cpx alias laravel/pint

如果不指定别名,系统会默认使用包的短名称;因此,上述第二行命令会创建名为 pint 的别名。别名存储在 ~/.cpx/ 目录下;使用 cpx aliases 可列出所有别名,使用 cpx unalias <name> 可删除指定别名。你也可以为包含多个可执行文件的包中的某个特定二进制文件设置别名。

另外还有两个值得了解的管理命令:cpx installed 用于列出通过 cpx 运行过的包,cpx clean 用于移除近期未使用的包(使用 --all 参数则会移除所有包)。请注意,现在的 cpx list 命令会显示可用的 cpx 命令(这是控制台程序的常规行为),而不再是显示已安装的包。

 运行 PHP 文件、Gist 代码片段及 REPL

cpx exec 和 cpx tinker 适用于运行临时脚本或快速执行一次性任务:

cpx exec script.php
cpx exec -r 'echo PHP_VERSION;'
cpx exec https://gist.github.com/user/id
cpx tinker

使用 Gist 支持功能时,程序会下载文件并在当前目录下运行。如果 Gist 包含多个 PHP 文件,cpx 会询问运行哪一个;你也可以在 Gist 页面链接后加上文件锚点(anchor)以跳过此提示。附加 SHA 哈希值可锁定特定版本,而设置 GITHUB_TOKEN 则能绕过 GitHub 的速率限制。

在代码实际运行前,这两个命令都会执行一些预处理工作。程序会在当前目录或上级目录中检测 Composer 的自动加载器(autoloader)。对于未显式导入(import)但 cpx 能找到匹配项的类,程序会自动为其创建别名。在 Laravel 项目中,应用程序会完成完整引导,配置(config)、Facades、.env 文件及 $app 实例均可用;在 Symfony 项目中,内核(kernel)会启动,并暴露 $kernel 和 $container。若需跳过此过程,可传入 --no-boot 参数。你的代码将在独立的 PHP 进程中运行,因此不会与 cpx 内置的依赖项发生冲突,且 exit() 退出码会正常传递。

cpx_require('nesbot/carbon');
 
echo Carbon\Carbon::now();

在安装了 laravel/tinker 的 Laravel 项目中,cpx tinker 会将任务移交给项目自身的 php artisan tinker,并透传诸如 --execute 之类的参数。在其他情况下,它会在项目已启动的环境中打开一个 PsySH shell。

智能体(Agent)感知输出

cpx 能够检测自身是否未连接到交互式终端。这涵盖了标准输入(stdin)被重定向、传入了 --no-interaction 或 -n 参数,以及在 AI 智能体内部运行(通过 laravel/agent-detector 进行识别)等情况。

在此模式下,子进程不会分配 TTY,提示符将回退为默认值,且管理命令(installed、aliases、alias、unalias、clean 和 update)将返回单行 JSON 数据:

{
    "success": true,
    "errors": [],
    "summary": {
        "packages": [
            { "name": "laravel/pint", "last_run": "2024-01-02 03:04:05" }
        ]
    }
}

在运行包(package)时,程序仅输出底层工具的原始输出,并抑制 cpx 自身的进度显示。cpx 层面出现的错误(例如命令无法识别或包无法安装)也会以 JSON 格式报告。在交互式终端中,若需获取同样的输出格式,请传入 --json 参数。若要在非交互模式下覆盖现有的别名,则必须使用 --force 参数。

安装与升级

cpx 2.0 要求 PHP 8.3 或更高版本。请使用 Composer 进行全局安装,并确保 Composer 的全局 bin 目录已添加到系统的 PATH 环境变量中:

composer global require cpx/cpx

了解更多

CPX 最初由 Liam Hammett 创建。如今,CPX 2.0 已成为 Laravel 官方维护的 laravel/cpx 软件包,并汇集了来自 Laravel 社区的多位贡献者。如果您想查看实时演示,可以参考 Taylor Otwell 在波士顿举行的 Laracon US 2026 大会首日主旨演讲中对 CPX 2.0 的介绍与演示。

您可以在 laravel/cpx GitHub 仓库中查阅完整的命令参考文档。如果您目前使用的是 1.x 版本,请参阅“从 1.x 升级到 2.x”的指南以开始使用 2.0 版本,同时也欢迎访问精美的项目主页 cpx.dev。