json_decode() 默认失败静默返回 null,需用 json_last_error() 检查;建议封装 safe_json_decode 函数主动抛异常,或 php 7.3+ 启用 json_throw_on_error。

json_decode() 返回 null 却没报错?检查 $json 和 $depth
PHP 的 json_decode() 默认失败时静默返回 null,不抛异常,这是最常被忽略的“假成功”。根本原因通常是 JSON 字符串本身非法(比如中文乱码、尾部逗号、单引号),或嵌套过深触发默认 $depth = 512 限制。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 调用后立刻用
json_last_error()判断:不是JSON_ERROR_NONE就说明解析失败 - 传入
true第二个参数强制返回数组,避免对象属性访问出错;若需对象,确保后续代码能处理null - 遇到深层嵌套结构(如日志、配置树),显式加大
$depth参数,例如json_decode($json, true, 2048) - 中文内容务必确认源字符串是 UTF-8 编码,
mb_detect_encoding($json) !== 'UTF-8'时先转码
想让 JSON 错误直接抛异常?用 json_decode() + 手动校验封装
PHP 原生不支持 json_decode() 抛出 Exception,必须自己兜底。强行用 set_error_handler() 捕获 E_WARNING 不可靠——它可能被其他 JSON 操作干扰,且无法区分具体哪次调用出错。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 写个简单封装函数,例如
safe_json_decode($json, $assoc = true, $depth = 512) - 内部调用
json_decode()后立即检查json_last_error(),非零则 throw new InvalidArgumentException(json_last_error_msg()) - 不要依赖
is_null()判断失败:合法 JSON 也可能解出null(如原始字符串就是"null") - 生产环境建议记录原始
$json片段(截取前 200 字符即可),方便排查上游数据问题
PHP 7.3+ 可以用 JSON_THROW_ON_ERROR,但要注意兼容性陷阱
这个 flag 看似一劳永逸,但它只控制 json_decode() 和 json_encode() 本身的错误是否抛出 JsonException,并不影响编码转换、内存超限等外围问题。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 启用方式是传入第四个参数:
json_decode($json, true, 512, JSON_THROW_ON_ERROR) - PHP PHP_VERSION_ID 或用
defined('JSON_THROW_ON_ERROR')守卫 -
JsonException是Exception子类,可用catch (Exception $e)捕获,但别漏掉catch (JsonException $e)做针对性处理 - 即使开了这个 flag,
json_last_error()仍会返回旧值(如JSON_ERROR_SYNTAX),不要混用两种错误机制
前端传来的 JSON 总是解析失败?重点查换行、BOM、不可见字符
真实接口中最常见的不是语法错误,而是肉眼不可见的污染:Windows 换行 \r\n 被当普通字符、UTF-8 BOM 头(\xEF\xBB\xBF)、富文本粘贴进来的零宽空格(\xE2\x80\x8B)。这些都会让 json_decode() 直接返回 null 且 json_last_error() 报 JSON_ERROR_SYNTAX。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 接收 POST body 后,先用
trim($raw)去首尾空白,再用preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $raw)清除控制字符 - 检测 BOM:
substr($raw, 0, 3) === "\xEF\xBB\xBF",有则substr($raw, 3) - 调试时用
bin2hex($raw)查看十六进制,比var_dump()更容易发现隐藏字符 - Nginx 或 Apache 若启用了 gzip,某些客户端未正确解压就发包,也会导致乱码——此时
$_POST已损坏,需在php://input层拦截处理
JSON 解析看着简单,真正卡住人的永远是那几个字节的编码偏差、换行差异或深度阈值。别迷信自动纠错,每次 json_decode() 后多一行 json_last_error() 检查,比事后翻日志快十倍。











