GraphQL联合类型响应不显式标注类型,需通过字段存在性判断分支;应优先json_decode后用数组逻辑识别,正则仅适用于流式片段或日志文本提取。

GraphQL响应中联合类型(Union)的JSON结构特征
联合类型在 GraphQL 响应里不会直接标出类型名,而是靠字段存在性或特定字段值来区分。比如 UserResult 是 User | Error 的联合,响应可能是:
{
"data": {
"getUser": {
"id": 123,
"name": "Alice"
}
}
}
也可能是:
{
"data": {
"getUser": {
"message": "Not found",
"code": "USER_NOT_FOUND"
}
}
}
正则无法“理解”语义,只能靠字段组合模式匹配 —— 这就是硬伤。别指望用一个 preg_match 吃下所有联合分支。
用正则提取前先做 JSON 结构预判
强行用正则解析嵌套 JSON 容易漏掉引号转义、换行、空格等细节,导致匹配失败。更稳妥的做法是:先 json_decode($response, true),再用 PHP 数组逻辑判断联合分支。
立即学习“PHP免费学习笔记(深入)”;
- 检查
$data['data']['getUser']是否有id字段 → 视为User - 检查是否有
message或code→ 视为Error - 若两者都不存在,或字段冲突(如同时有
id和message),说明 Schema 设计有问题,正则更没法救
如果非要用正则(比如日志文件里捞原始响应片段),至少限定范围:只对 "getUser":\s*{.*?} 这种已知键名+大括号块做捕获,再对子串二次匹配,而不是扫整个 JSON 字符串。
正则写法必须避开的三个坑
即使你坚持用正则,以下写法极易翻车:
-
/\"id\"\s*:\s*(\d+)/—— 忽略了id可能是字符串("id": "abc123")、null、或根本不存在;联合类型里它本就不该稳定出现 -
/\{([^}]*)\}/—— 遇到嵌套对象(如"posts": [{"title": "..."}])立刻崩,贪婪匹配会截断 - 用
preg_match_all扫整个响应体 —— 一旦errors字段存在且结构相似,就会把错误信息误当成正常数据提取
真正能用的底线正则,仅限于提取「已知键名下的标量值」,例如:/"email"\s*:\s*"([^"]+)"/,且前提是确认该字段在当前联合分支中一定存在。
什么时候正则反而比 json_decode 更合适?
只有两种真实场景值得考虑正则:
- 处理未完整返回的流式响应片段(如 SSE 或 chunked HTTP body),还没凑成合法 JSON,但你知道某段结构固定,比如
"status":"ok"出现在每个块开头 - 从 nginx access log 或 debug 日志中提取 GraphQL 请求体里的某个字段(此时根本不是 JSON,只是文本日志)
除此之外,所有对完整 GraphQL 响应体的操作,请直接走 json_decode + 数组判断。联合类型的本质是运行时多态,正则连编译时类型都抓不住,更别说运行时分支了。



















