Menu

PHP json_encode():把数组和对象转换为 JSON

json_encode($value) 把 PHP 数组、对象或标量转换为 JSON 字符串。关联数组变成 JSON 对象,列表变成 JSON 数组,JSON_PRETTY_PRINT 和 JSON_UNESCAPED_UNICODE 等标志用来控制输出。

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

json_encode($value) 返回一个 PHP 值对应的 JSON 文本。关联数组变成 JSON 对象,列表(键为 0, 1, 2...)变成 JSON 数组,字符串、数字、true、false 和 null 则变成对应的 JSON 值。

输出:

{"name":"Ada","age":36,"langs":["php","js"],"admin":true,"manager":null}
string

结果是一个普通字符串,可以直接发送给浏览器、存进文件或数据库的列,或者传给另一个程序。要把 JSON 转回 PHP,请使用 json_decode()。

格式化输出 JSON

json_encode() 的第二个参数接受标志。JSON_PRETTY_PRINT 会加上换行和 4 个空格的缩进,配置文件或调试日志中需要的正是这种格式。多个标志用 | 组合:

输出:

{
    "app": "shop",
    "debug": false,
    "db": {
        "host": "localhost",
        "port": 3306
    },
    "tags": []
}

让中文、日文等 UTF-8 文本保持可读

默认情况下,json_encode() 会把每个非 ASCII 字符写成 \u 转义,并在每个 / 前面加上反斜杠。两者都是有效的 JSON,解码后也能还原成同样的文本,但会让输出难以阅读,而且更长。JSON_UNESCAPED_UNICODE 会保留原始字符,JSON_UNESCAPED_SLASHES 会让 URL 保持原样:

输出:

{"name":"\u308a\u3093\u3054","price":120,"url":"https:\/\/example.com\/fruit\/apple"}
{"name":"りんご","price":120,"url":"https://example.com/fruit/apple"}

如果解码后文本显示为乱码,问题并不在转义上:这个字符串一开始就不是 UTF-8。json_encode() 只接受 UTF-8,遇到其他编码会返回 false,详见下面关于错误的一节。

数组什么时候会变成对象而不是列表

只有当键正好按顺序为 0, 1, 2... 时,PHP 数组才会编码为 JSON 数组。其他任何键都会让它变成 JSON 对象。在 unset() 或 array_filter() 之后,键中会留下空缺,这一点常常让人措手不及:

输出:

{"0":"apple","2":"cherry"}
["apple","cherry"]
{"1":"a","2":"b"}
[]
{}
{"0":"a","1":"b"}

只要接收方的代码期望得到一个列表,编码前就调用 array_values()。如果对方期望的是一个可能为空的对象,就使用 new stdClass() 或 (object) $array,这样空值也会输出为 {}。

编码对象,并用 JsonSerializable 控制它的 JSON

普通对象只会编码它的 public 属性;protected 和 private 属性会被跳过。要精确决定一个对象在 JSON 中的样子,就实现 JsonSerializable 接口,并在 jsonSerialize() 中返回数据:

输出:

{"name":"Ada","nick":null}
{"date":"2026-03-14 09:30:00.000000","timezone_type":3,"timezone":"UTC"}
{
    "id": 7,
    "total": 19.5,
    "created": "2026-03-14T09:30:00+00:00"
}

像 enum Status: string 这样的回退枚举(backed enum)会编码为它的值("active")。纯枚举没有值,所以 json_encode() 遇到它会失败,并提示 "Non-backed enums have no default serialization"。

数字、浮点数和数字字符串

整数和浮点数会写成 JSON 数字,字符串即使只包含数字也仍然是字符串。有三个标志可以改变这种行为:

输出:

{"price":10}
{"price":10.0}
0.30000000000000004
{"qty":"3","id":"007"}
{"qty":3,"id":7}

JSON_NUMERIC_CHECK 会转换每个数字字符串,所以像 "007" 这样的 ID 或像 "01234" 这样的邮政编码会丢失前导零。与其对整个数组使用它,不如用 (int) 只转换你需要的字段。

json_encode 返回 false:找出错误

无法编码某个值时,json_encode() 会返回 false。常见原因是字符串不是有效的 UTF-8(从旧文件或 Latin-1 数据库中读出的文本),以及浮点值 NAN 和 INF。json_last_error_msg() 会说明出了什么问题;JSON_THROW_ON_ERROR 则会让它抛出 JsonException:

输出:

bool(false)
Malformed UTF-8 characters, possibly incorrectly encoded
{"name":"Caf\ufffd"}
{"name":"Café"}
JsonException: Inf and NaN cannot be JSON encoded

在新代码中,JSON_THROW_ON_ERROR 是更好的默认选择:一个没人检查的 false 最终会被当作空字符串存储或发送出去。

从 PHP API 返回 JSON

用 JSON 响应的 PHP 脚本要在输出任何内容之前设置 Content-Type 响应头,编码一次,然后结束:

<?php
header('Content-Type: application/json; charset=utf-8');

$products = [
    ['id' => 1, 'name' => 'りんご', 'price' => 120],
    ['id' => 2, 'name' => 'みかん', 'price' => 80],
];

echo json_encode(['data' => $products], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
exit;

如果要在 HTML 的 <script> 标签中输出 JSON,请加上 JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT。默认的斜杠转义会把 </script> 变成 <\/script>,但只要有人加上 JSON_UNESCAPED_SLASHES,这层保护就没了,而且值中的 <!-- 仍然会改变浏览器解析脚本的方式。这些标志会把 \u003C、\u003E、\u0026、\u0027 和 \u0022 写成 \u003C、\u003E、\u0026、\u0027 和 \u0022,JavaScript 读取时会还原成同样的字符。

常见问题

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

把它传给 json_encode():json_encode(['name' => 'Ada', 'age' => 36]) 返回 {"name":"Ada","age":36}。键按顺序为 0, 1, 2... 的数组则会变成 JSON 数组:json_encode(['a', 'b']) 返回 ["a","b"]。

PHP 中怎么格式化输出 JSON?

加上 JSON_PRETTY_PRINT 标志:json_encode($data, JSON_PRETTY_PRINT) 会用 4 个空格缩进,并把每个值放在单独的一行。多个标志用 | 组合,例如 JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE。

为什么 json_encode 会把中文、日文等文本变成 \u 编码?

默认情况下,每个非 ASCII 字符都会写成 \uXXXX 转义,所以 りんご 会变成 \u308a\u3093\u3054。这仍然是有效的 JSON,但传入 JSON_UNESCAPED_UNICODE 可以让字符保持可读。

json_encode 为什么返回 false?

通常是因为某个字符串不是有效的 UTF-8,或者数据中包含 NAN 或 INF。调用 json_last_error_msg() 查看原因,或者传入 JSON_THROW_ON_ERROR,让它抛出 JsonException 而不是返回 false。

怎么让 json_encode 对空数组输出 {} 而不是 []?

空的 PHP 数组总是编码为 []。要得到空对象,使用 new stdClass() 或 (object) [],或者使用 JSON_FORCE_OBJECT 标志,它会把值中的每个数组都变成对象。

Coddy 编程语言插图

和 Coddy 一起学编程

开始