Composer脚本中应通过$event->getComposer()->getPackage()->getExtra()获取composer.json的extra配置,而非直接读取文件或使用getenv(),以确保兼容版本解析、环境变量插值及平台配置。

Composer 脚本里怎么拿到 composer.json 里的配置项
Composer 脚本(比如 scripts 中定义的命令)默认不自动加载项目配置,但可以通过 Composer\IO\IOInterface 和 Composer\Package\RootPackageInterface 拿到解析后的 composer.json 内容。关键不是“读文件”,而是复用 Composer 自己解析好的配置对象。
常见错误是直接 file_get_contents('composer.json') —— 这会绕过 Composer 的版本解析、平台配置、替换逻辑(如 replace)、甚至环境变量插值(${env:FOO}),导致行为不一致。
- 脚本函数签名必须接收
$event参数(Composer\Script\Event类型) - 通过
$event->getComposer()->getPackage()获取根包对象,它已包含所有合并后的配置 -
extra字段内容可通过$package->getExtra()安全获取,这是最常用入口
如何在自定义脚本中读取 extra 配置并做条件判断
extra 是 Composer 推荐给用户存放自定义配置的位置,比如构建参数、部署标识、调试开关。脚本里读它既安全又符合约定。
// scripts/Deploy.php
public static function deploy($event)
{
$package = $event->getComposer()->getPackage();
$extra = $package->getExtra();
// 确保字段存在且类型正确
$target = $extra['deploy_target'] ?? 'staging';
$dryRun = ($extra['dry_run'] ?? false) === true;
if ($dryRun) {
echo "DRY RUN: would deploy to {$target}\n";
return;
}
// 实际部署逻辑...
}
-
extra中的值不会被自动类型转换(比如 JSON 里的true在 PHP 数组里还是布尔) - 避免直接访问
$extra['foo']['bar'],先判空或用 null 合并操作符 - 如果需要结构化配置,建议在
extra下统一加前缀(如myapp.config),避免和其它插件冲突
为什么不能在脚本里直接用 getenv() 读系统环境变量
可以读,但要注意:Composer 脚本运行时的环境变量,和你在 shell 里执行 composer install 时的环境并不完全等价——尤其是通过 CI 工具(如 GitHub Actions、GitLab CI)触发时,某些变量可能被隔离或未透传。
- 推荐方式:在
composer.json的config.platform.env中显式声明要注入的变量名,Composer 会把它塞进PlatformRepository,再通过$event->getComposer()->getConfig()->get('platform')->get('env')取 - 更简单的方式:把关键变量写进
extra,CI 流程先用sed或jq替换composer.json再运行脚本,可控性更强 - 不要依赖
$_SERVER或getenv()读COMPOSER_HOME、HOME等路径类变量,不同系统行为不一致(Windows vs Linux)
post-install-cmd 和 post-autoload-dump 的配置可见性差异
不是所有脚本钩子都能访问完整配置。例如 post-autoload-dump 触发时,Composer 可能尚未完成整个依赖图解析,$event->getComposer()->getPackage() 返回的对象可能缺少某些动态生成的字段(如 autoload 合并结果)。
-
pre-install-cmd/post-install-cmd/pre-update-cmd/post-update-cmd这些生命周期钩子,能拿到完整的RootPackageInterface -
post-autoload-dump主要用于处理自动加载逻辑,适合读autoload配置,但不适合读extra中与部署强相关的字段 - 如果脚本逻辑依赖
extra且必须在 autoloader 生成后执行,建议拆成两个脚本:一个在post-install-cmd里把extra写入临时 JSON 文件,另一个在post-autoload-dump里读那个文件
真正容易被忽略的是:Composer 脚本的执行上下文是 Composer 自身进程,不是你的应用代码。哪怕你用了 autoload-dev,脚本里也**不会自动加载**你项目里的类——除非你手动 require 或用 Composer 的 autoload 加载机制注册。这点和 Laravel 的 Artisan 命令完全不同。











