脚本必须定义在composer.json顶层scripts字段下,键名须为内置事件(如post-install-cmd)或合法自定义名,值须为可执行命令或php回调,且php类需被autoload正确加载。

composer.json 里怎么写 scripts 才算生效
脚本必须放在 scripts 字段下,且键名不能是 Composer 内置事件(如 post-install-cmd)以外的任意字符串——否则它只是个“未注册的命令”,composer xxx 会报错 Command "xxx" is not defined。
真正能直接运行的自定义命令,得满足两个条件:一是键名不冲突,二是值必须是可执行的 shell 命令或 PHP 脚本路径。比如:
"scripts": {
"hello": "echo 'Hi from composer!'",
"serve": "php -S localhost:8000 -t public",
"migrate": "@php artisan migrate --no-interaction"
}
-
@php是 Composer 内置语法,表示用当前 PHP 解释器执行后续命令,避免硬写php可能导致路径不一致 - 多个命令可用数组形式,每项单独执行;单条命令用字符串更清晰,也方便调试
- 如果命令里含空格或特殊符号(如
&&),建议拆成数组项,否则 shell 解析可能出错
为什么 post-install-cmd 里的 migrate 总是失败
最常见原因是 artisan 文件不存在或不在当前工作目录——Composer 的生命周期钩子默认在项目根目录执行,但如果你的 artisan 在 bin/ 或 app/ 下,或者项目还没装完 Laravel,php artisan migrate 就会报 Command "migrate" is not defined。
解决方式不是加路径,而是确保命令可被发现:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 检查
vendor/bin/是否有artisan符号链接(Laravel 安装后通常有) - 改用完整路径调用:
"@php ./artisan migrate --no-interaction"(注意开头的./) - 更稳妥的做法是用 PHP 脚本封装逻辑,在脚本里判断框架是否存在、加载 autoloader 再调命令,避免 shell 层面的路径和依赖盲区
- 别忘了加
--no-interaction,否则 CI 环境会卡住等待输入
如何让自定义命令支持传参
Composer 原生不支持命令行参数透传,composer hello world 中的 world 会被忽略。想实现类似效果,只有两种可靠路径:
- 用 shell 函数封装:在
~/.zshrc里写hello() { php scripts/hello.php "$@"; },然后source ~/.zshrc,之后就能hello --env=local - 在 PHP 脚本里解析
$argv:比如scripts/migrate.php接收$argv[1]当作环境标识,再决定是否加--force - 不要试图在
scripts字段里拼接"php script.php $1"——$1不会被 shell 展开,这是 Composer 解析机制决定的,不是权限或配置问题
scripts 和插件(plugin)到底该选哪个
简单任务用 scripts,复杂逻辑或跨项目复用才值得写插件。scripts 是声明式、轻量、无需安装的;插件是编程式、可监听事件、能改 Composer 行为本身,但要注册类型、实现接口、处理 autoload。
一个容易被忽略的边界是:scripts 无法修改依赖解析过程,也不能拦截 require 动作;而插件可以在 pre-dependency-resolution 阶段动态替换包版本,甚至拒绝安装某些包。
所以当你发现自己在多个项目里复制粘贴同一段 scripts,还总要修路径、判环境、加 try/catch,那差不多就是该抽成插件的时候了——但别低估它的维护成本,一个没写好 autoload 的插件会让整个 composer install 失败且无提示。










