PHP 7+ 的 json_decode 使用原生 C 解析器而非 JS 引擎,基于 RFC 7159 进行词法与语法分析,递归下降解析并由 $depth 参数控制最大嵌套深度(默认 512),超限返回 null 并触发 JSON_ERROR_DEPTH。

PHP 7+ 的 json_decode 使用原生解析器,不是 JavaScript 引擎
很多人误以为 json_decode 是调用 V8 或其他 JS 引擎,其实完全不是。PHP 7.0 起就弃用了旧的 Douglas Crockford JSON checker,改用自己实现的原生 C 解析器,直接在 Zend 引擎层处理 UTF-8 字节流。它不依赖外部库,也不执行任何 JS 代码——只是按 RFC 7159 规则做词法分析 + 语法树构建。
递归下降解析 + 深度计数器是栈安全的核心机制
每次遇到 { 或 [,解析器就递归进入下一层,并将当前深度加 1;遇到 } 或 ] 则回退。这个计数器由第三个参数 $depth 控制,默认值是 512,对应常量 PHP_JSON_PARSER_DEFAULT_DEPTH。
- 超出时不会崩溃,而是立即返回
null,并让json_last_error()返回JSON_ERROR_DEPTH - 深度不是“对象层数”或“数组层数”的简单相加,而是所有嵌套结构(对象/数组混合)的总递归调用次数
- 设为
1时,连{"a":1}都会失败,因为根对象本身就算一层
assoc 参数不改变解析过程,只影响结果构造阶段
$assoc 参数(第二个)只在解析完成、构建 PHP 变量时起作用:解析器始终先生成内部 AST,再根据该参数决定把每个 JSON 对象节点转成 stdClass 还是 array。它不影响性能,也不影响错误判断逻辑。
- 设为
true:所有对象都变成关联数组,包括嵌套对象 - 设为
false(默认):顶层和所有子对象都是stdClass实例 - PHP 8.2+ 支持
null值配合JSON_OBJECT_AS_ARRAY标志位,语义更明确
大整数和特殊选项(如 JSON_BIGINT_AS_STRING)在解析末期才介入
数字解析本身是统一的:先按 double 或 int 解析原始字面量,再根据 $options 决定是否“降级”处理。比如 JSON_BIGINT_AS_STRING 不是在读取时就当字符串,而是在数字类型判定完成后,检查是否超出 PHP_INT_MAX,再强制转为字符串。
立即学习“PHP免费学习笔记(深入)”;
- 这意味着即使启用了该选项,
9223372036854775807(刚好等于PHP_INT_MAX)仍会是 int,而9223372036854775808才变 string -
JSON_THROW_ON_ERROR是 PHP 7.3+ 新增的“开关”,它不改变解析行为,只是把原本要静默返回null的错误转成JsonException抛出 - 所有选项都在解析完成后一次性应用,没有中间态或流式干预
json_last_error() 返回的是 JSON_ERROR_SYNTAX,跟 JSON_ERROR_DEPTH 完全不同。



















