自定义 Composer 脚本需严格满足三要素:脚本名必须定义在顶层 scripts 字段(非 scripts-dev,除非显式加 --dev)、命令须用字符串或数组格式正确声明(推荐 ["@php", "-S", "localhost:8000"] 保障跨平台)、参数传递必须用 -- 显式分隔且由脚本自行解析(如 $argv 或 $@),否则静默失败或报“Script not found”。

直接说结论:自定义 Composer 脚本不是“写个命令就能跑”,关键在 scripts 字段的结构、执行上下文和参数传递机制——错一个地方,composer run-script xxx 就会静默失败或报 Script not found。
脚本名写在哪?scripts 还是 scripts-dev?
Composer 2.2+ 支持 scripts-dev 字段,但默认不启用。如果你把脚本放在 scripts-dev 里,却只运行 composer run-script dev-server,就会报错 Script not found: dev-server。
- 日常开发用的自定义命令(如
dev-server、test-ci)建议统一放scripts,避免环境差异 - 真要隔离 dev-only 脚本,必须显式加
--dev参数:composer run-script dev-server --dev -
scripts-dev不会自动合并进scripts,也不会被生命周期事件(如post-install-cmd)触发
字符串 vs 数组写法:为什么 "serve": "php -S localhost:8000" 在 Windows 上常失败?
字符串值会被当作 shell 命令交给系统执行。Linux/macOS 下没问题,但 Windows 默认用 cmd.exe,不识别 -S 语法,且空格、引号处理混乱。
- 改用数组格式更安全:
"serve": ["@php", "-S", "localhost:8000"] -
@php强制调用 Composer 自带的 PHP(路径稳定、版本可控),不依赖$PATH - 数组中每个元素是独立参数,跨平台无歧义;字符串则需 shell 解析,容易因空格、重定向、变量展开出错
怎么传参数给脚本?composer run-script build -- --env=prod 为什么 $_SERVER['argv'] 里没有 --env=prod?
因为 composer run-script 默认不透传参数。只有两种方式能拿到外部参数:
- Shell 类脚本(字符串或数组):必须手动在命令里处理
$@,例如"build": "bash build.sh $@",然后在build.sh里解析$1、$2 - PHP callable 脚本(如
"check": "My\Build::run"):Composer 会把--后所有内容作为$argv数组传入静态方法,无需额外解析 - 注意:
--是分隔符,不是可选的;漏写它,参数会被composer自己消费掉
长时间运行的脚本(比如本地服务器)为什么卡住没输出?
Composer 默认捕获子进程的 stdout/stderr,并只在失败时打印最后几行。对 php -S 或监听类命令,这会导致看起来“卡死”,实际已在运行。
- 加
-v(verbose)看实时输出:composer run-script serve -v - 或者用
--no-interaction避免交互阻塞(某些 CLI 工具会检测 TTY) - 生产环境慎用这类脚本;本地开发可用,但别放进 CI 流程——CI 会超时
最易被忽略的一点:脚本里调用的 PHP 类(如 MyScript::run)必须能被 Composer 自动加载。如果类在 autoload.files 或 PSR-4 规则外,会直接报 Class not found,而不是脚本执行失败——错误信息里甚至不提 autoload,排查起来特别绕。











