json_encode() 默认转义中文,PHP 5.4前需预处理转UTF-8;5.5+失败统一返回false,须显式检查;数据库、连接层、PHP内部编码必须均为UTF-8。

json_encode() 默认不处理中文,老版本连选项都不支持
PHP 5.2 刚引入 json_encode(),连 JSON_UNESCAPED_UNICODE 都没有——这个常量直到 5.4 才定义。所以你在 5.3 或更早版本里写 json_encode($data, JSON_UNESCAPED_UNICODE),会直接报 undefined constant 错误。
此时想让中文不被转成 \u4f60\u597d,只能靠预处理:
- 用
iconv('GBK', 'UTF-8//IGNORE', $str)或mb_convert_encoding($str, 'UTF-8', 'GBK')强制转码 - 不能依赖
mb_internal_encoding()的默认值:PHP 7.3 及以前默认是ISO-8859-1,7.4+ 才改默认为UTF-8 - 所有字符串输入前必须确认是 UTF-8,否则
json_encode()直接返回false
PHP 5.5+ 开始返回值变严格,false 不再是“偶尔出现”
5.5 之前,json_encode() 失败时可能返回空字符串或 null;5.5 起统一为 false。这不是修复,是暴露问题——比如你从 MySQL 拿数据没设连接编码,字段含 ? 或乱码字节,json_encode() 就静默失败。
必须显式检查返回值:
立即学习“PHP免费学习笔记(深入)”;
if ($json === false) { error_log('JSON encode failed: ' . json_last_error_msg()); }- 别用
empty($json)判断,因为false、''、null都会被判为 true-ish - 数据库连接层要配好:
mysqli_set_charset($conn, 'utf8mb4')或执行SET NAMES utf8mb4
PHP 7.4 → 8.0:null 键数组不再自动转对象,但 array_is_list() 才是关键
PHP 7.4 中 json_encode([null => 'a']) 输出 {"": "a"},看起来像对象;8.0 仍输出相同字符串,但内部对“是否为列表”的判断更保守。真正影响的是你后续怎么解码和用它。
常见踩坑点:
- 用
json_decode($str)(无第二个参数)后试图$obj->""访问,PHP 8.0+ 会报错,而 7.x 可能容忍 - 别再用
array_keys($arr) === range(0, count($arr)-1)判定索引数组,PHP 8.0+ 下不可靠 - PHP 8.1+ 推荐用
array_is_list($arr);8.0 及以下可用!array_diff_key($arr, array_values($arr))
浮点数、NaN、INF 在 PHP 7.1+ 后不再被静默转换
PHP 7.1 前,json_encode(NAN) 返回 "null",json_encode(INF) 返回 "null";7.1+ 改为直接报错并返回 false,且 json_last_error() 返回 JSON_ERROR_INF_OR_NAN。
如果你的数据里有计算结果可能产出 INF 或 NAN(比如除零、对数负数),就得提前过滤:
array_walk_recursive($data, function(&$v) { if (is_float($v) && (!is_finite($v))) $v = null; });- 金额字段别用
float存——老项目升级时发现float字段导出 JSON 失败,换成decimal后就正常了 -
json_encode(null)在 7.1+ 返回"null"字符串,之前版本返回false,注意前端是否依赖该行为
最易被忽略的其实是数据源头:MySQL 字段编码、连接层字符集、PHP 内部 mbstring 编码三者不一致,比任何 json_encode() 选项都更容易导致失败。别急着调参数,先确认 mb_check_encoding($data, 'UTF-8') 全部返回 true。



















