如何使用Composer exec命令执行vendor/bin中的脚本? (统一入口)

13次阅读

composer exec 不自动补全路径、不加载项目 autoloader、不切换至项目根目录,导致“Command not found”等错误;应显式指定路径或改用 composer run-script。

如何使用Composer exec命令执行vendor/bin中的脚本? (统一入口)

直接用 composer exec 就能跑 vendor/bin 下的工具,但必须注意它不自动补全路径、不加载项目 autoloader、且默认工作目录不是项目根目录——很多报错都源于这三点。

为什么 composer exec phpunit 会报 “Command not found”

Composer 默认不会把 vendor/bin 加入 PATH,也不会帮你 cd 到项目根目录。它只是简单地调用 proc_open() 执行命令,而该命令在当前 shell 环境下找不到可执行文件。

  • 确保你在项目根目录(即有 composer.json 的地方)运行命令
  • 不要依赖系统 PATH 查找 phpunit,应显式写成 composer exec vendor/bin/phpunit 或用 -- 分隔符传参
  • 如果脚本是 PHP 写的(如 phpstanpsalm),它可能依赖项目 autoloader,此时需加 --no-dev--with-dependencies 不起作用——exec 本身不加载 autoload

composer exec 的参数传递规则

它用 -- 区分 composer 自己的选项和要传给目标命令的参数。漏掉 -- 会导致参数被 composer 吞掉或解析错误。

  • 正确: composer exec -- phpunit --testdox tests/Unit
  • 错误: composer exec phpunit --testdox tests/Unit--testdox 被当成 composer 参数,报错 Unknown option)
  • 想指定 PHP 版本?得用 COMPOSER_PHP_BINARY=/usr/bin/php8.2 composer exec -- phpunit,不能用 -d--php

替代方案:用 composer run-script 更可靠

如果你的工具已定义在 composer.jsonscripts 里(比如 "test": "phpunit"),优先用 composer testcomposer run-script test -- --testdox。它会自动切换到项目根目录,并支持 autoload-dev 加载。

  • composer run-script 会触发 post-autoload-dump 等钩子,exec 完全不会
  • 脚本中可用 $COMPOSER_BIN_DIR 环境变量(值为 vendor/bin),比硬编码路径更安全
  • 需要动态参数?用 composer run-script lint -- --level=5 src/-- 后的内容透传给脚本定义里的命令
{     "scripts": {         "cs-fix": "php-cs-fixer fix --dry-run --diff",         "analyze": [             "@psalm",             "@phpstan"         ],         "psalm": "psalm --no-cache",         "phpstan": "phpstan analyse --no-progress"     } }

真正容易被忽略的是:无论用 exec 还是 run-script,只要脚本本身调用了 require_once 'vendor/autoload.php',就必须保证它运行时的当前工作目录是项目根目录——否则相对路径失效,autoload.php 找不到。

text=ZqhQzanResources