php中json_encode()不能直接处理mysql查询结果,需先用mysqli_fetch_all($result, mysqli_assoc)或pdo::fetch_assoc转为关联数组,并处理tinyint布尔、datetime格式、null值、中文编码(加json_unescaped_unicode)及大结果集分页等问题。

PHP 用 json_encode() 直接转 MySQL 查询结果会出错
不是所有 MySQL 返回的数据都能直接塞进 json_encode() —— 比如 mysqli_result 对象、NULL 字段里的 MySQL TEXT 或 BLOB,还有时间字段(DATETIME)在某些旧版本 PHP 里会变成空字符串或报错。
常见错误现象:json_encode() expects parameter 1 to be array, object given,或者输出一堆 null 和空对象。
- 必须先用
mysqli_fetch_all($result, MYSQLI_ASSOC)或PDOStatement::fetchAll(PDO::FETCH_ASSOC)把结果集转成纯数组 - 如果用了
MYSQLI_NUM,JSON 字段名会是数字索引,前端难处理,一律用MYSQLI_ASSOC - MySQL 的
TINYINT(1)常被当布尔用,但 PHP 里还是整数,json_encode()不会自动转true/false,得手动映射
中文乱码?别只盯着 mysql_set_charset()
即使设置了 utf8mb4 连接,json_encode() 默认不加 JSON_UNESCAPED_UNICODE,中文会被转成 \uXXXX 形式——这不是乱码,是默认行为;但有些前端解析器(尤其老版本 Axios 或某些小程序 SDK)对 Unicode 转义支持不稳定。
- 务必加上第二个参数:
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) - 连接层也要确认:MySQL 服务端字符集是
utf8mb4,数据库/表/列都是utf8mb4_unicode_ci,PHP 连接时执行了SET NAMES utf8mb4 - 用 PDO 更稳妥:
$pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4")
DateTime 和 NULL 字段怎么安全转 JSON
MySQL 的 DATETIME 在 PHP 里是字符串,但有时带微秒或时区信息,json_encode() 会原样输出;而 NULL 列如果被误判为字符串 "NULL" 或空字符串,前端就收不到预期的 null 值。
立即学习“PHP免费学习笔记(深入)”;
- 统一在取数据后做清理:用
array_map()遍历每行,对已知日期字段用date('c', strtotime($val))标准化,或直接用DateTime对象的format('c') - 显式过滤掉无效值:
isset($row['updated_at']) && $row['updated_at'] !== '0000-00-00 00:00:00'再赋值,否则设为null - 避免用
empty()判NULL,它会把0、"0"、false全干掉;改用is_null()或严格比较=== null
大结果集别一次性 json_encode(),也别漏设 header
查几万行再 json_encode(),内存爆、响应慢、还容易触发 PHP 的 memory_limit;另外没设 Content-Type: application/json; charset=utf-8,Chrome 会当 HTML 解析,中文显示成小方块。
- 用
header('Content-Type: application/json; charset=utf-8')开头就发,别等 echo 后再补 - 超 1000 行建议分页,或用
yield+json_encode()流式输出(需配合ob_flush()和flush(),但注意 Nginx 缓存可能截断) - 调试时用
json_last_error()和json_last_error_msg()看具体哪步崩了,比 var_dump 猜快得多
最常被忽略的是:MySQL 字段类型和 PHP 数据类型的隐式转换边界,比如 DECIMAL(10,2) 查出来是字符串还是 float,会影响 JSON 数字精度;别全靠 json_encode() 自动猜,该 cast 就 cast,该 round 就 round。











