@php和@composer是Composer内置别名,分别替换为当前PHP路径和composer.phar路径,确保环境一致;脚本中应优先使用数组格式传参,调用其他脚本时用composer run而非@composer run。

脚本里怎么用 @php、@composer 这类内置别名
Composer 提供了以 @ 开头的“内部命令别名”,本质是让脚本复用当前 Composer 进程已加载的 PHP 环境或自身二进制,避免硬编码路径或版本错配。最常用的是 @php 和 @composer。
它们不是 shell 别名,也不依赖系统 PATH;而是 Composer 在执行脚本前主动替换的占位符:
-
@php→ 替换为当前运行 Composer 的 PHP 可执行文件路径(比如/usr/bin/php8.2),确保与 autoload、扩展兼容 -
@composer→ 替换为当前 composer.phar 所在路径(如/usr/local/bin/composer),可用于递归调用自身命令
错误写法:"dev": "php -S localhost:8000" —— 会调用系统默认 php,可能不匹配项目要求的版本或扩展;正确写法:"dev": "@php -S localhost:8000"。
为什么 @composer install 在脚本里有时不生效
直接在 scripts 中写 @composer install 很容易失败,核心原因是:Composer 默认禁止“嵌套执行”防止死循环,且不自动继承当前工作目录和参数。
常见现象包括:
- 报错
Script not found: install(误以为@composer install是调用一个叫install的脚本) - 静默退出,实际什么都没做(子进程被限制输出,且未启用
--no-interaction) - 在 Windows 下因路径分隔符或 shell 解析差异彻底失败
安全做法是显式加 --no-interaction 并确认当前目录就是项目根(composer.json 所在):
"reinstall": "@composer install --no-interaction"
如果需要带 --dev 或自定义仓库配置,必须完整写出,不能依赖交互式提示。
数组格式脚本比字符串更可靠
脚本值写成数组(而非字符串),能绕过 shell 解析层,规避空格、引号、特殊字符问题,也更容易跨平台。
对比:
- 危险字符串:
"test": "php vendor/bin/phpunit --filter TestName"——--filter后的空格和参数在某些 shell 下会被截断或误解析 - 推荐数组:
"test": ["@php", "vendor/bin/phpunit", "--filter", "TestName"]—— 每个元素独立传参,无歧义
注意:数组第一项必须是可执行命令路径,@php 和 @composer 在数组中同样有效;但 @php 不能出现在数组中间位置(只认首项)。
想在脚本里跑另一个自定义脚本,该用 composer run 还是 @composer run
一律用 composer run,不要写 @composer run。
原因很直接:@composer 是给底层命令(如 install、dump-autoload)用的,而 run 是 Composer 的顶层子命令,本身就需要通过 CLI 入口启动。写成 @composer run xxx 会导致双重封装,大概率报 Command "run" is not defined(尤其在旧版 Composer 中)。
正确示例:
"build-all": ["composer run build-js", "composer run build-php"]
或者单行字符串(仅当逻辑简单时):
"ci": "composer run lint && composer run test"
关键点:跨脚本调用时,确保被调用脚本名拼写完全一致(大小写、连字符)、存在于 scripts 字段顶层,且没被 scripts-dev 隔离(除非加 --with-dependencies 或明确启用 dev 脚本)。
最容易被忽略的是工作目录继承——所有 composer run xxx 子调用都共享父脚本启动时的当前目录,不会自动 chdir 到某个子包路径。如果脚本要操作子模块,得自己 cd 或用绝对路径。











