scripts 必须位于 composer.json 根层级,与 name、require 并列;PHP 脚本需手动引入 vendor/autoload.php;推荐使用 @php 而非 php 以确保 PHP 版本和自动加载一致。

scripts 字段必须写在 composer.json 顶层
脚本定义不生效,90% 是因为放错了位置。它必须是 composer.json 根对象的直接子字段,不能嵌套在 extra、config 或其他任意字段里。
常见错误:把脚本写成这样(✘):
{
"extra": {
"scripts": {
"dev:clear": "php clear.php"
}
}
}
正确写法(✔):
{
"scripts": {
"dev:clear": "php clear.php"
}
}
-
scripts是顶层 key,和name、require并列 - 值可以是字符串(单条命令)、字符串数组(顺序执行)、或关联数组(含
script+description) - 自定义脚本名如
dev:clear不会自动触发,必须显式运行composer run dev:clear
PHP 脚本里必须手动 require autoload.php
直接写 php scripts/test.php 却报 Class not found?不是 Composer 问题,是你脚本没加载自动加载器。
Composer 只负责调用 shell 命令,不帮你初始化 PHP 环境。哪怕脚本在项目根目录下,use AppServicesLogger; 也会失败。
- 脚本开头必须有
require __DIR__.'/vendor/autoload.php'; - 路径要用
__DIR__,别依赖当前工作目录(getcwd()可能是任意路径) - 如果脚本需要 CLI 参数,用
$argv解析,别指望$_SERVER['argv']总是一致 - 加
#!/usr/bin/env phpshebang 行后,可设为可执行并直接运行(如./scripts/test.php),但composer run仍推荐用@php前缀确保版本一致
@php 和 php 的区别不只是语义
@php 不是装饰符,它是 Composer 内置指令,强制使用 Composer 当前配置的 PHP 可执行路径(比如通过 platform.php 或 config.bin-dir 控制),而裸写的 php 会走系统 $PATH 查找。
- CI 场景下尤其关键:本地开发用 PHP 8.3,CI runner 默认是 8.1,裸写
php可能跳过平台约束 -
@php还能绕过某些 shell 限制(比如 Windows 下 cmd 对引号的解析异常) - 错误示例:
"dev:test": "php test.php --verbose"→ 改成"dev:test": "@php test.php --verbose" -
@php后面不能跟空格再接参数;参数要紧贴在脚本路径后,如@php scripts/run.php --env=prod
框架命令别直接写 php artisan migrate
直接在 scripts 里写 php artisan migrate 很容易在 CI 或不同用户环境下失败,原因不是命令错,而是执行上下文缺失。
典型报错:Class 'AppConsoleKernel' not found 或 Command not found: artisan。
- 正确做法是调用
vendor/bin/artisan(它本身是带 shebang 和 autoload 的封装脚本) - 加上
--no-interaction和--force,避免交互卡住或生产环境误提示 - 示例:
"post-update-cmd": ["@php vendor/bin/artisan migrate --no-interaction --force"] - 如果逻辑复杂(比如要先检查 DB 连接再迁移),别堆命令行,改用自定义 PHP 类方法(如
"pre-deploy": "App\Scripts\DeployCheck::run"),并在autoload中注册命名空间
真正难的从来不是“怎么写”,而是“在哪执行、用谁的 autoloader、以什么 PHP 版本、带什么环境变量”。脚本一旦脱离本地开发机,这些细节就会立刻暴露。别省那两行 require 和一个 @ 符号。











