composer run-script 后需加 -- 分隔自定义参数,否则会被 Composer 解析丢弃;脚本中通过 $_SERVER['argv'] 手动解析,推荐使用数组格式命令确保跨平台和参数透传可靠性。

composer run-script 后面的参数怎么传进去
直接在命令末尾加 --,再跟上你自己的参数,比如 composer run-script build -- --env=prod。不加 --,参数会被 Composer 自己吃掉,脚本里根本收不到。
常见错误现象:写了 composer run-script deploy prod,结果 PHP 脚本里 $argv 只有 ['deploy'] —— 因为没用 -- 分隔,Composer 把 prod 当作子命令或选项处理了。
实操建议:
-
--必须紧挨着脚本名之后,不能漏、不能多写一个空格 - 参数顺序不影响,但所有自定义参数都得放在
--后面 - 如果脚本是数组格式(如
["php", "build.php"]),参数会原样透传给php build.php;如果是字符串格式(如"php build.php"),shell 解析可能出错,优先用数组
PHP 脚本里怎么拿到这些参数
Composer 不会自动把参数塞进 $argv 或 $argc,它只负责把 -- 后面的内容原样传给执行进程。所以你得自己解析。
典型做法是用 $_SERVER['argv'] 读取完整命令行,然后跳过前两个元素(php 和脚本路径),再逐个检查是否以 -- 开头:
$args = array_slice($_SERVER['argv'], 2);
$env = 'dev';
foreach ($args as $arg) {
if (str_starts_with($arg, '--env=')) {
$env = substr($arg, 6);
break;
}
}
注意点:
- 别用
$argv全局变量——它在某些 SAPI(如 Apache mod_php)下不可靠 - 别依赖
getopt(),因为 Composer 不保证传入的是标准 POSIX 参数格式 - 如果脚本是 callable(如
"App\Scripts\Build::run"),参数会作为$event->getArguments()返回,这是更干净的方式
环境变量和参数混用时容易踩的坑
很多人想用 COMPOSER_SCRIPT_ENV=prod composer run-script build,但这个环境变量在脚本里读不到——因为 Composer 启动子进程时默认不继承父进程的环境变量,除非显式配置。
正确做法是把关键上下文转成参数传进去,或者用 putenv() 在脚本开头手动注入:
putenv('APP_ENV=' . ($env ?? 'dev'));
更稳妥的方案是统一走参数,避免环境变量路径错乱问题:
-
COMPOSER_SCRIPT_APP_ENV这类变量只在 Composer 内部脚本生命周期中有效,外部 shell 调用不生效 - 如果你用
@php调用另一个 PHP 文件,那个文件默认读不到当前脚本的putenv()设置,得重新传 - 在 CI 环境中,
export APP_ENV=prod && composer run-script build是无效的,必须用-- --env=prod
为什么数组格式脚本比字符串格式更可靠
写成 "build": ["php", "scripts/build.php"] 比 "build": "php scripts/build.php" 少一堆 shell 解析陷阱。
比如你想传带空格的路径:--output=/var/www/my app/build,字符串格式下 shell 会把它拆成两个参数,数组格式则原样透传。
还有几个硬伤:
- Windows 下字符串格式常因
cmd.exe解析规则失败,数组格式跨平台一致 - 字符串格式无法捕获 exit code 细节,出错时 Composer 只报 “Script terminated with error code”,查不到具体哪一行崩了
- 数组格式支持
@php前缀,能强制使用 Composer 自带的 PHP 版本,避免系统 PATH 混乱
参数传递这件事本身不复杂,但一旦混入环境变量、跨平台执行、子进程嵌套,就很容易在部署时静默失败。最稳的路是:全用数组格式 + -- 显式分隔 + PHP 脚本内手动解析参数,别图省事拼字符串。











