应优先精简数据结构并缓存json_encode()结果,而非调优函数参数;php8.1变慢主因是数据更复杂(嵌套对象、资源句柄、循环引用),非函数本身退化。

直接缓存 json_encode() 的结果,而不是每次请求都重新编码;对大数组做结构精简和提前过滤,比调优函数参数更有效。
为什么 json_encode() 在 PHP8.1 里对大数据变慢
PHP8.1 默认启用 serialize_precision 更严格的浮点处理,且深度递归时会做更多类型检查;如果原始数据含大量嵌套对象、资源句柄(哪怕只是未显式 unset 的 PDOStatement)、或循环引用,json_encode() 会在内部反复探测并 fallback,导致耗时非线性增长。不是函数本身变慢,而是你传进去的数据“变得更难编”了。
- 用
json_last_error()检查返回 false 时,大概率是中途 abort,不是卡死 -
JSON_PARTIAL_OUTPUT_ON_ERROR可让编码不中断,但输出可能缺字段——别在生产接口默认开 - 对象若没实现
JsonSerializable,PHP 会反射所有 public 属性,字段越多越慢
先判断是否真要 encode 整个数组
很多接口返回的“大 JSON”其实包含大量冗余字段(如调试用的 trace_id、未授权的 user.permissions、空数组 logs => []),这些字段不仅增加编码时间,还放大传输体积。
- 用
array_filter($data, function($v) { return $v !== null && $v !== [] && $v !== ''; })清理空值(注意不要误删 0 或 false) - 对敏感字段或高成本字段(如 base64 图片、长文本摘要)改用懒加载:返回占位符
"avatar_url": "/api/v1/user/123/avatar",而非直接塞进 JSON - 前端真正需要的字段通常不到后端组装数据的 30%,用白名单裁剪:
array_intersect_key($data, array_flip(['id', 'name', 'status']))
缓存编码结果比优化 flags 更立竿见影
如果你的接口数据更新频率低(比如配置、地区列表、静态商品目录),重复调用 json_encode() 是纯 CPU 浪费。APCu 缓存字符串比缓存数组再 encode 快 3–5 倍,因为跳过了类型遍历和 UTF-8 校验。
- 必须先
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),再检查$json === false,只缓存成功结果 - 缓存键别拼接原始数组(
md5(serialize($data))太重),用业务 ID + 版本号,例如sprintf('catalog_v2_%d', $category_id) - 避免用
JSON_PRETTY_PRINT缓存——多出来的换行和空格既占内存又无传输优势 - 若用 Redis,存
$json字符串,别存$data数组——反序列化开销更大,且 Redis 不识别 PHP 类型
大整数和浮点数容易触发隐式截断
PHP8.1 对大整数(如雪花 ID、bigint 主键)默认转成 float,再 encode 就会丢失精度;而 json_encode() 对 float 的处理依赖 serialize_precision ini 设置,该值若为 14(默认),16 位以上数字就不可靠。
- 加
JSON_BIGINT_AS_STRING:确保"id": "12345678901234567890"而不是"id": 12345678901234567890 - 对价格等关键浮点字段,统一转 string 存储:
'price' => sprintf('%.2f', $price),避免前端 JS 解析误差 - 别依赖
JSON_THROW_ON_ERROR抓大数问题——它只在语法错误时抛异常,精度丢失仍静默发生
最常被忽略的是:你以为在优化 json_encode(),实际瓶颈在数据组装阶段——比如一次查库拉回 1000 条记录再 foreach 构造数组。先砍数据量,再谈编码效率。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











