PHP json_decode JSON_THROW_ON_ERROR 怎样统一处理解析失败
给 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 能保证输入安全吗?
不能。它只是解析失败通道,不能替代请求大小控制、字段规则、权限或业务约束。
是否需要先解析一次检查,再解析一次取值?
本例只解码一次,再对解码值做结构判断。这样解析结果与业务检查针对的是同一个值。
PHP mb_strtolower 怎样正确处理中文与多字节文本
- 上一篇
- PHP mb_strtolower 怎样正确处理中文与多字节文本
- 下一篇
- PHP 日期解析警告怎样用 getLastErrors 识别
-
- 文章 · php教程 | 24分钟前 |
- PHP array_intersect_key 怎样按键保留配置字段
- 368浏览 收藏
-
- 文章 · php教程 | 26分钟前 | php Composer 自动加载 autoload-dev require-dev
- PHP Composer autoload-dev 怎样隔离开发依赖
- 375浏览 收藏
-
- 文章 · php教程 | 28分钟前 |
- PHP session.use_strict_mode 怎样拒绝未知会话 ID
- 382浏览 收藏
-
- 文章 · php教程 | 30分钟前 |
- PHP password_get_info 怎样读取哈希算法和成本参数
- 229浏览 收藏
-
- 文章 · php教程 | 40分钟前 |
- PHP fputcsv 怎样避免字段中的逗号破坏 CSV
- 111浏览 收藏
-
- 文章 · php教程 | 46分钟前 |
- PHP 日期解析警告怎样用 getLastErrors 识别
- 477浏览 收藏
-
- 文章 · php教程 | 52分钟前 |
- PHP mb_strtolower 怎样正确处理中文与多字节文本
- 350浏览 收藏
-
- 文章 · php教程 | 54分钟前 | php 输入校验 filter_var FILTER_VALIDATE_EMAIL FILTER_VALIDATE_URL
- PHP filter_var 怎样校验 URL 与邮箱地址
- 491浏览 收藏
-
- 文章 · php教程 | 57分钟前 | PHP · php 数组分组 array_reduce 累加器
- PHP array_reduce 怎样累积生成分组结果
- 398浏览 收藏
-
- 文章 · php教程 | 11小时前 | PHP · php-fpm ·
- PHP OPcache interned_strings_buffer 的内存规划与容量排查
- 498浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 719次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 726次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 801次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 762次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 599次使用
-
- PHP fgetcsv escape 参数显式设置与 RFC 4180 兼容处理
- 2026-10-26 501浏览
-
- PHP JSON_THROW_ON_ERROR 抛错后怎么保留原始字段位置
- 2026-09-09 501浏览
-
- PHP 8.5 array_last() 怎么处理空数组:从 null 结果到兼容旧版本的 Polyfill
- 2026-08-16 501浏览
-
- 宝塔配置Ruby环境:RVM+Nginx反代教程
- 2026-05-29 501浏览
-
- unset函数作用范围详解
- 2026-05-29 501浏览

