PHP 7.3 下 json_encode() 输出中文为 \u4f60\u597d 或 null,根本原因是数据源非 UTF-8 或输出未声明 charset=utf-8;JSON_UNESCAPED_UNICODE 仅控制是否转义,不修复编码错误,需逐环节验证 UTF-8 状态并设置 header('Content-Type: application/json; charset=utf-8')。

PHP 7.3 下 json_encode() 输出中文变成 \u4f60\u597d 或直接返回 null,不是 PHP 有 bug,而是编码链路上某处断了。核心就两条:数据源必须是 UTF-8,输出通道必须声明 UTF-8。
为什么加了 JSON_UNESCAPED_UNICODE 还是乱码或 null
这个标志只控制“是否转义中文”,不负责“修复非 UTF-8 字符”。一旦输入字符串含 GBK/BOM/混合编码,json_encode() 会静默失败并返回 false(不是空字符串,是布尔 false),你 echo 出来就啥都看不到。
- 用
var_dump(json_encode($data, JSON_UNESCAPED_UNICODE))检查返回值——如果是bool(false),立刻查json_last_error_msg() - 常见报错:
"Malformed UTF-8 characters"(数据本身不是 UTF-8)、"Invalid type"(对象里有资源句柄或闭包) - 数据库连的是
utf8而不是utf8mb4?MySQL 的utf8实际只支持 3 字节 UTF-8,emoji 和部分生僻汉字会截断成非法序列 - PHP 文件自身带 BOM 头?用编辑器另存为“UTF-8 无 BOM”格式
header('Content-Type: application/json; charset=utf-8') 必须在 echo 前且无任何输出
即使 json_encode() 正确输出了中文,浏览器仍可能显示方块或问号,因为 HTTP 响应头没生效。PHP 的 header() 只能在任何内容输出前调用。
- 检查文件开头有没有空格、BOM、
echo、print、警告(E_WARNING)甚至注释前的不可见字符 - 用
ob_start()开启缓冲,再用ob_clean()清掉已缓存的杂音,再发 header ——但这是补救,不是常态方案 - Nginx/Apache 配置里如果有
charset GBK或AddDefaultCharset,会强行覆盖 PHP 的 header,得关掉 - 用 curl -I 或浏览器开发者工具 Network 标签页确认响应头里真有
Content-Type: application/json; charset=utf-8
从 MySQL 读中文进 JSON 的典型踩坑点
PHP 7.3 默认用 PDO 或 mysqli,但连接层编码常被忽略。光设数据库表字段为 utf8mb4 不够,连接时也得声明。
- PDO 构造时加选项:
new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']) - mysqli_connect 后立刻执行:
mysqli_set_charset($conn, 'utf8mb4') - 不要依赖
SET CHARACTER SET utf8mb4,它不改 client/connection 层编码 - 用
mb_detect_encoding($str, ['UTF-8', 'GB18030'], true)检查从数据库取出来的单个字段是否真为 UTF-8;若不是,用mb_convert_encoding($str, 'UTF-8', 'GB18030')强制转
最易被忽略的是“数据进来时已经坏了”——比如前端 POST 提交的表单没设 accept-charset="UTF-8",或 HTML 页面 meta 是 GB2312,那 PHP 收到的就是 GBK 字节流,后面所有 json_encode() 操作都徒劳。验证环节不能跳:每个环节(前端→PHP接收→DB查询→JSON编码→HTTP输出)都要单独确认编码状态,而不是只盯着最后一行 echo json_encode(...)。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











