PHP json_decode JSON_THROW_ON_ERROR 怎样统一处理解析失败
来源:17golang原创
时间:2026-10-26 22:57:28 312浏览 收藏
给 json_decode() 的第四个参数传入 JSON_THROW_ON_ERROR,再在统一输入边界捕获 JsonException,就能把语法、编码和嵌套深度等解析失败集中处理。合法 JSON null 仍会正常返回 PHP 的 null,业务字段是否合格则需要另行判断。
官方手册:https://www.php.net/manual/en/function.json-decode.php。本文以箱件数量接口为例,示例使用 PHP 8.0+ 语法和行为,未运行代码。该标志本身从 PHP 7.3 起提供。
先保护输入结果的可信度
我会把这个问题拆成三种责任:入口控制数据规模,解析器确认 JSON 能否被解码,业务层确认结果是否符合接口契约。这样遇到失败时,能知道该修改发送内容、字段规则还是程序配置。
假设接口只接受一个包含整数 count 的对象,并要求数量介于 1 和 1000。这里要保护的是一条可用的业务记录,以及不会夹带原始报文的错误记录。风险既可能来自意外截断、错误编码,也可能来自不符合预期的大体积或深层输入;这些都不应被默认转换成一条“空记录”继续处理。
字节上限应在读取请求时就由服务器、框架或读取逻辑配合约束。本文函数里的长度判断只能限制已经读入的字符串,不能撤销此前发生的读取和内存占用。

把解析失败集中到 JsonException
旧代码如果只判断返回值是否为 null,会混淆两种情况:输入是合法的 JSON null,或者输入根本解析失败。启用异常后,解析失败进入 catch,合法值仍走正常返回路径;不要再把 json_last_error() 当作这次异常模式调用的主要错误来源。
JSON 常量文档明确说明,该标志使用异常替代原先通过全局错误状态读取失败的方式。错误类型可以从 $error->getCode() 取得,说明文字则来自异常消息。统一处理应依赖明确错误分类,而不是匹配一段可能变化的英文报错文本。
下面的函数故意不在内部吞掉解析异常,让入口调用者决定如何返回错误。
65536) {
throw new LengthException('输入超过接口允许的字节数');
}
// 对象保留为 stdClass,便于区分 JSON 对象与数组
// 32 是示例允许的嵌套深度,按实际接口契约配置
$value = json_decode($raw, false, 32, JSON_THROW_ON_ERROR);
if (!$value instanceof stdClass) {
throw new UnexpectedValueException('顶层必须是 JSON 对象');
}
// 类型和范围属于业务约束,解析器不会替我们确认
if (!property_exists($value, 'count')
|| !is_int($value->count)
|| $value->count count > 1000) {
throw new UnexpectedValueException('count 必须是 1 到 1000 的整数');
}
// 仅输出业务需要的字段,不直接透传任意输入属性
return ['count' => $value->count];
}
解析成功后继续检查业务结构
JSON 能被解析,并不代表输入就是接口需要的对象。null、布尔值、字符串、数字和数组都可能是合法 JSON。示例选择 associative=false,并要求返回值是 stdClass,从而把顶层对象与数组区分开。
接下来检查 count 是否存在、是否为整数以及范围是否合格。字符串 "12" 与整数 12 在此契约中不同;是否允许字符串转换,应由业务明确决定,不能依赖隐式转换恰好成功。
这个函数只返回 count 字段,其他输入属性没有进入返回记录。它没有实现完整 JSON Schema,也不承担账号权限、业务幂等或数据库约束;需要这些控制时,应放到对应业务层继续处理。
对我来说,提前分清这些责任比把所有异常包装成同一句“JSON 格式错误”更有用:调用方不会为了修复字段范围问题,反复调整一份语法本来正确的 JSON。
为失败分支保留最少审计信息
true, 'data' => $parcel];
} catch (JsonException $error) {
// 不写入原始报文,只记录请求标识和解析错误码
error_log(sprintf(
'request_id=%s stage=json_decode json_code=%d',
$requestId,
$error->getCode()
));
$result = ['ok' => false, 'error' => 'invalid_json'];
} catch (LengthException $error) {
// 超配额是入口拒绝,不伪装成 JSON 语法异常
$result = ['ok' => false, 'error' => 'payload_too_large'];
} catch (UnexpectedValueException $error) {
// 业务结构错误使用独立错误分类
$result = ['ok' => false, 'error' => 'invalid_payload'];
}
示例把三类预期失败映射成三个稳定标识:invalid_json、payload_too_large 和 invalid_payload。这只是应用层结果对象,不是完整 HTTP 控制器;接入框架时,再按接口协议设置响应状态、响应头和序列化方式。
审计记录只展示固定请求标识、阶段和解析错误码。生产环境的请求标识应由服务端生成或经过规范化,日志访问范围与保留期限由项目管理。不要为方便排查就把整段请求体、令牌或个人数据拼进日志,也不要直接向外部调用者回传异常堆栈。

这里没有捕获所有 Throwable 并一律返回 invalid_json。比如 PHP 8 中把 depth 配成不在允许范围内的值,会触发 ValueError;这属于调用参数错误,与报文的嵌套超过一个合法深度上限不同。上层统一异常处理器仍要承担意外程序错误的记录与响应。
按输入类型确认处理边界
下表是从代码和手册推导的处理预期,用来说明输入契约,未声称已运行这些案例。
| 输入情形 | 应归属的位置 | 示例结果分类 |
|---|---|---|
| 对象含 count 整数 12 | 解析与字段检查均满足 | ok 为 true |
| 合法 JSON null | 业务顶层对象要求 | invalid_payload |
| 对象末尾多一个逗号 | JSON 解析 | invalid_json |
| count 是字符串或超范围 | 业务字段规则 | invalid_payload |
| 字符串长度超过示例配额 | 入口字节配额 | payload_too_large |
| 报文超过合法设置的解析深度 | JSON 解析 | invalid_json |
保持深度限制与实际结构相称,也不要为了让编码错误消失就随意加入 JSON_INVALID_UTF8_IGNORE 或 JSON_INVALID_UTF8_SUBSTITUTE。这些选项会改变无效 UTF-8 的处理方式;是否接受丢弃或替换字符,应由字段含义与接口契约决定。
启用异常后,null 就一定是错误吗?
不是。JSON null 是合法值;示例拒绝它是因为本接口要求对象,而不是解析器失败。
捕获 JsonException 能保证输入安全吗?
不能。它只是解析失败通道,不能替代请求大小控制、字段规则、权限或业务约束。
是否需要先解析一次检查,再解析一次取值?
本例只解码一次,再对解码值做结构判断。这样解析结果与业务检查针对的是同一个值。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
368 收藏
-
375 收藏
-
382 收藏
-
229 收藏
-
111 收藏
-
477 收藏
-
350 收藏
-
491 收藏
-
398 收藏
-
241 收藏
-
498 收藏
-
501 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习