Menu

PHP json_decode():把 JSON 解析为数组或对象

json_decode($json, true) 把 JSON 字符串转换为 PHP 关联数组;不传 true 时得到的是 stdClass 对象。学习读取嵌套的值、用 JSON_THROW_ON_ERROR 处理错误、json_validate(),以及 json_decode 为什么返回 null。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

json_decode($json, true) 把 JSON 字符串转换为 PHP 值,每个 JSON 对象都变成一个关联数组。省略 true 时,JSON 对象会变成 stdClass 对象,需要用 -> 读取。无效的 JSON 会得到 null。

输出:

Ada
js
Ada
php
Array
(
    [name] => Ada
    [age] => 36
    [langs] => Array
        (
            [0] => php
            [1] => js
        )

    [admin] => 1
)

无论选择哪种模式,JSON 数组总是变成 PHP 列表。反方向从 PHP 转成 JSON,请用 json_encode()。

关联数组还是对象:true 与 false

两种模式保存的数据相同;选择在你的代码中读起来更顺的那种即可。数组可以配合所有数组函数使用(array_column、array_map、isset($data['key'])),所以大多数代码都传 true。如果键不是合法的属性名,例如带连字符或者是数字,对象就需要使用花括号语法:

输出:

Ada zero London
Ada zero London
object(stdClass)#2 (1) {
  ["city"]=>
  string(6) "London"
}

第四个参数用于传入标志。JSON_OBJECT_AS_ARRAY 也会返回数组,但前提是第二个参数为 null(它的默认值):json_decode($json, flags: JSON_OBJECT_AS_ARRAY) 返回数组,而 json_decode($json, false, 512, JSON_OBJECT_AS_ARRAY) 仍然返回对象。

遍历嵌套的 JSON

API 响应通常是一个对象里包含一个对象列表。解码一次,然后用 foreach 遍历,对可能缺失的字段使用 ??:

输出:

#1 Ada <ada@example.com> roles: admin, editor
#2 Linus <no email> roles: none
#3 Grace <grace@example.com> roles: editor
Array
(
    [1] => Ada
    [2] => Linus
    [3] => Grace
)

处理无效的 JSON

对于无效的 JSON,json_decode() 返回 null,但对于 JSON 文本 null,null 也是正确的结果,所以单凭 null 无法判断是否失败。json_last_error_msg() 会给出上一次调用的出错原因。要在一份很长的文档中找到出错位置,可以把它粘贴到 JSON 格式化工具 中,它会指出出错的那一行。更简洁的做法是使用 JSON_THROW_ON_ERROR,它会抛出 JsonException:

输出:

NULL
Syntax error
NULL
No error
Invalid JSON: Syntax error

第三个参数 512 是最大嵌套深度(默认值)。使用命名参数可以跳过它:json_decode($json, true, flags: JSON_THROW_ON_ERROR)。

用 json_validate() 检查字符串是否为有效的 JSON

PHP 8.3 新增了 json_validate()。它只回答 true 或 false,不会构建解码后的数组,所以当你只需要一个“是”或“否”时,它比解码占用更少的内存,例如可以用来尽早拒绝无效的请求体:

输出:

'{"a": 1}'    valid
'[1, 2, 3]'   valid
'"text"'      valid
'{a: 1}'      invalid: Syntax error
'{\'a\': 1}'  invalid: Syntax error
''            invalid: Syntax error

如果你反正都要使用这些数据,就跳过 json_validate(),直接用 JSON_THROW_ON_ERROR 解码:先验证会让字符串被解析两次。

读取 JSON 文件

用 file_get_contents() 读取文件,再解码字符串。这段代码会先写入 settings.json,这样才有文件可读:

输出:

Theme: dark
Plugins: 2
{
    "theme": "dark",
    "fontSize": 16,
    "plugins": [
        "git",
        "lint"
    ]
}

json_decode 为什么返回 null:常见原因

JSON 比 JavaScript 和 PHP 的数组语法更严格。下面每个字符串看起来都没问题,但每一个都返回 null。运行代码查看各自的原因,然后修正其中一个,再运行一次:

输出:

single quotes    Syntax error
unquoted key     Syntax error
trailing comma   Syntax error
comment          Syntax error
byte order mark  Syntax error
too deep         Maximum stack depth exceeded
float(1.2345678901234567E+19)
string(20) "12345678901234567890"

字节顺序标记在大多数编辑器中都看不见,它是 JSON 文件“看起来没问题”却无法解码的经典原因。解码前用 $text = preg_replace('/^\xEF\xBB\xBF/', '', $text); 把它去掉。

常见问题

PHP 中怎么把 JSON 转换成数组?

把 true 作为第二个参数传入:json_decode('{"name":"Ada"}', true) 返回 ['name' => 'Ada'],然后用 $data['name'] 读取值。不传 true 时,JSON 对象会变成 stdClass 对象,需要写 $data->name。

json_decode 为什么返回 null?

可能是 JSON 无效(单引号、末尾逗号、键没有加引号、字节顺序标记),嵌套深度超过了限制,或者这段 JSON 本身就是 null。检查 json_last_error_msg(),或者用 JSON_THROW_ON_ERROR 解码,得到一个说明原因的 JsonException。

PHP 中怎么检查一个字符串是不是有效的 JSON?

从 PHP 8.3 开始,json_validate($string) 返回 true 或 false,而不必构建解码后的值。在更早的版本中,先解码,再检查 json_last_error() === JSON_ERROR_NONE。

PHP 中怎么读取 JSON 文件?

先读取文件,再解码:$data = json_decode(file_get_contents('data.json'), true, flags: JSON_THROW_ON_ERROR);。文件不存在时 file_get_contents() 会返回 false,所以要先检查这一点。

PHP 中怎么访问带连字符的 JSON 键?

解码成数组后用 $data['first-name'],如果是对象则用花括号:$obj->{'first-name'}。同样的花括号语法也适用于数字键,例如 $obj->{'0'}。

Coddy 编程语言插图

和 Coddy 一起学编程

开始