composer scripts跨平台判断需用php脚本中转或platform配置兜底:优先写bin/check-env.php用php_os_family分支执行,纯json方案仅适用于ci预设平台场景。

Composer 的 scripts 怎么做跨平台条件判断
Composer 本身不支持 if/else 语法,scripts 字段里写的只是 shell 命令字符串,直接写 [ "$OSTYPE" = "linux-gnu" ] && echo "Linux" 在 Windows 上会报错——因为 CMD/PowerShell 根本不认识方括号语法。真正能落地的方案只有两条路:靠外部脚本中转,或用 Composer 自带的 platform + 环境变量组合兜底。
- 优先写成独立脚本(如
bin/check-env.php),在scripts里统一调用:"post-install-cmd": "php bin/check-env.php",由 PHP 判断PHP_OS_FAMILY或$_SERVER['OS'],再分发命令 - 若坚持纯 JSON 配置,可利用 Composer 的
config.platform.php配合环境变量,但仅适用于「预设目标平台」场景(比如 CI 中强制指定为 Linux);真实运行时仍以宿主系统为准 - Windows 下 CMD 和 PowerShell 混用极易出问题:比如
npm run dev在 CMD 可行,但在 Git Bash 里可能因路径分隔符(/vs\)失败,建议所有脚本开头加set -e(Bash)或$ErrorActionPreference = "Stop"(PowerShell)提前中断
为什么 composer.json 里的 scripts 不能直接用 && 或 ||
不是语法不支持,而是执行器不可控。Composer 启动脚本时,会根据当前系统选择 shell:Linux/macOS 走 /bin/sh,Windows 默认走 CMD(哪怕你用 Git Bash 启动)。CMD 不认 && 的短路逻辑,command1 && command2 会被整个当做一个命令名报“找不到程序”。更隐蔽的问题是,某些命令(如 php -v)在不同 shell 下退出码含义不一致,导致条件链断裂。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
-
composer run-script build实际等价于sh -c "your-command"(Linux/macOS)或cmd /c "your-command"(Windows),二者对空格、引号、重定向的解析规则完全不同 - 别依赖
$PATH里有某个命令:Windows 上find是系统命令,Linux 上是 GNU findutils,行为差异极大;应显式用which find或command -v find检查 - 如果必须内联写,Linux/macOS 用
sh -c 'test "$(uname)" = "Linux" && echo ok',Windows 则只能退化为两个独立 script 条目,靠 CI 工具(如 GitHub Actions 的if: runner.os == 'Windows')分发
用 symfony/console 写可复用的跨平台命令脚本
比硬塞 shell 逻辑更可持续的做法,是把条件判断收口到一个 PHP 命令行工具里。安装 symfony/console 后,你可以定义带参数和选项的命令,比如 php bin/run-platform-task.php --os=auto build,内部用 PHP_OS_FAMILY 做分支,还能加日志、错误提示、交互确认。
-
PHP_OS_FAMILY比PHP_OS更可靠:返回Linux/Windows/Darwin,不含版本号干扰,且 PHP 7.2+ 全平台支持 - 避免在脚本里拼接路径:用
dirname(__DIR__)+PATH_SEPARATOR,而不是硬写../vendor/bin/xxx,否则 Windows 下\和/混用会触发file_exists()返回 false - 调试时加
echo "Running on: " . PHP_OS_FAMILY;,别只信php_uname('s')——Docker 容器里它返回的是容器 OS,不是宿主,而PHP_OS_FAMILY是编译时确定的,更稳定
跨平台脚本最麻烦的从来不是判断逻辑,而是路径处理和子进程环境继承。比如在 Windows 上用 proc_open() 调 npm,如果没显式传入 env 参数,子进程会丢失 Composer 设置的 COMPOSER_HOME,导致缓存路径错乱。这些细节,光靠 scripts 字段的字符串根本压不住。










