composer run-script 从 composer.json 的 "scripts" 字段查找匹配键名的脚本,按 php/shell/callable 类型分发执行;未定义则报“script not found”;默认不启用 scripts-dev,需 --no-dev 或显式启用;字符串脚本走 shell(跨平台风险高),数组格式如 ["php", "artisan"] 更安全;@php 调用 composer 自带 php;参数需 -- 显式分隔并在脚本中处理;默认捕获输出,长时间脚本易误判卡死,可用 -v 查看详情;php -r 即时执行但难维护且无法访问 autoload 类,callable 可复用、支持 $event 对象但要求类可自动加载且方法为 public static。

composer run-script 命令到底在执行什么
它不是直接调用 Shell 命令,而是从 composer.json 的 "scripts" 字段里找键名匹配的脚本定义,再按类型(php、shell、callable)分发执行。没定义就报错:Script not found: ...。
常见错误现象:明明写了 "dev": "php -S localhost:8000",却执行 composer run-script dev 报错——因为没加 --no-dev 或脚本被 "scripts-dev" 隔离了(Composer 2.2+ 支持),但默认不启用。
- 脚本值是字符串时,默认走 shell 执行(跨平台风险高)
- 脚本值是数组时,第一个元素是命令路径,后续是参数,更安全(如
["php", "artisan", "optimize"]) - 含
@前缀(如@php)表示调用 Composer 自带的 PHP 可执行文件,避免环境 PHP 版本不一致
怎么让自定义脚本支持参数传递
原生 composer run-script 不解析脚本后参数,composer run-script build -- --env=prod 中的 --env=prod 默认被忽略。必须显式用 -- 分隔,并在脚本定义里预留接收位置。
使用场景:构建命令传环境变量、测试命令传过滤器、部署脚本传分支名。
- Shell 类脚本需手动处理
$@,例如:"deploy": "bash deploy.sh $@" - PHP callable 脚本(如
"check": "My\Script::run")会自动把--后参数作为$argv传入静态方法 - 用
symfony/console封装的命令建议直接注册为 Composer 插件,而非硬塞进 scripts
为什么有些脚本执行后没输出或卡住
Composer 默认捕获子进程 stdout/stderr,只在失败时吐出最后几行。遇到长时间运行的脚本(如本地服务器、监听任务),容易误判为“卡死”。
性能与兼容性影响:Windows 下某些 shell 脚本(尤其是含重定向或管道)可能无法正确继承终端控制权;PHP 内置服务器在非 TTY 环境下会静默退出。
- 加
-v或--verbose查看完整执行过程和真实错误 - 交互式脚本(如需要 readline 输入)必须加
--no-interaction=false,否则会被强制禁用 - 后台服务类脚本建议加
&并配合nohup,但要注意 Composer 进程退出后子进程可能被 kill(Linux 默认行为)
scripts 里写 php -r 和写 callable 有什么区别
"test": "php -r "var_dump('hello');"" 是即时解释执行,调试方便但难维护;"test": "My\Test::run" 是调用已加载类的静态方法,依赖自动加载,适合复用逻辑。
容易踩的坑:callable 必须是可 autoload 的类,且方法得是 public static;若类不在 autoload 配置里,会抛 Class not found,而不是脚本未找到。
-
php -r不能访问 Composer 加载的类(除非手动 require vendor/autoload.php) - callable 方式能拿到完整的
$event对象(ComposerScriptEvent实例),可读取当前运行阶段、IO 接口、composer 实例等 - PHP 版本差异:
php -r在 PHP 8.1+ 对某些语法(如短闭包嵌套)更敏感,而 callable 由运行时 PHP 解析,更稳定
复杂点在于 callable 的加载时机和作用域隔离——它跑在 Composer 主进程里,不是 fork 出的新进程,所以全局状态(如 error_reporting 设置、已 include 的文件)会相互影响。这点常被忽略。











