php用json_encode()输出json需主动控制编码行为和http头:设content-type、用json_unescaped_unicode和json_invalid_utf8_substitute,排查false时用json_last_error(),大数据用generator流式处理,防响应污染。

PHP 用 json_encode() 输出 JSON,但默认不保证标准格式
直接调用 json_encode($data) 通常能工作,但容易产出非标准 JSON:比如中文被转成 \uXXXX、null 值被忽略、浮点数精度丢失,或响应头没设对导致前端解析失败。
关键不是“能不能出 JSON”,而是“前端能不能直接 JSON.parse() 不报错”。所以得主动控制编码行为和 HTTP 头:
- 加
JSON_UNESCAPED_UNICODE避免中文变 Unicode 转义 - 加
JSON_INVALID_UTF8_SUBSTITUTE(PHP 7.2+)防止非法 UTF-8 字符崩掉整个输出 - 必须手动设置
Content-Type: application/json; charset=utf-8 - 遇到
null或空数组时,json_encode()默认输出null或[],这本身合法,但若业务要求统一结构,得提前补默认字段
示例:
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE);
遇到 json_encode() returns false 怎么快速定位
返回 false 不代表数据“空”或“错”,绝大多数是编码前数据含不可序列化内容,比如资源句柄、闭包、循环引用对象,或字符串本身含非法 UTF-8 字节。
立即学习“PHP免费学习笔记(深入)”;
别急着改逻辑,先做三件事:
- 用
json_last_error()和json_last_error_msg()看具体错误类型,比如JSON_ERROR_UTF8就说明某字段混入了 GBK 编码的字符串 - 用
mb_check_encoding($str, 'UTF-8')逐个检查字符串字段是否真为 UTF-8 - 对对象导出,优先用
JsonSerializable接口定义jsonSerialize()方法,而不是依赖默认对象属性遍历
常见坑:MySQL 查询结果里用 mysql_real_escape_string(已废弃)或手动拼接字符串后没转 UTF-8,入库时看似正常,导出时突然 json_encode() 失败。
导出大数组时内存爆掉或超时,怎么安全分块
json_encode() 是一次性加载全部数据进内存再编码的。10 万行记录直接 json_encode($rows) 很可能 OOM 或触发 max_execution_time。
真要导出大量数据,别硬扛:
- 用
yield+Generator流式生成 JSON 片段,配合ob_flush()分批输出(注意 Web 服务器缓冲策略) - 避免把整张表
SELECT *全读进 PHP 数组;改用游标分页查,每次取 1000 行,json_encode()后立即echo并flush() - 如果只是给前端下载文件,不如用
fopen('php://output', 'w')写 CSV,比 JSON 轻量得多——JSON 是为结构化交互设计的,不是大数据导出格式
记住:JSON 导出 ≠ 数据导出。选对格式比调参更重要。
API 接口返回 JSON,但前端收不到或解析报错
90% 不是 PHP 编码问题,而是响应体被意外污染:开头/结尾多了一个空格、BOM 字节、或 error_log() / var_dump() 残留输出。
排查顺序很固定:
- 用
curl -i或浏览器 DevTools 的 Network → Response Headers 查看原始响应头,确认Content-Type是application/json,且没有X-Powered-By之类干扰项 - 用
curl -s http://your-api | hexdump -C | head看前几个字节有没有ef bb bf(BOM),有就用vim以:set nobomb保存文件 - 确保入口脚本(如
index.php)前后没有空行、空格、?>后的换行——PHP 的短标签或=结尾尤其容易带空格
最稳妥的做法:在输出 JSON 前加 ob_end_clean() 清空所有缓冲区,再设 header、再 echo json_encode(...),一气呵成。











