应使用 microtime(true) 多次循环测试 json_encode/json_decode 耗时,取中位数或最小值,避免单次测量受冷启动、opcache、jit 预热不足及系统抖动影响。

PHP 中怎么测 json_encode 和 json_decode 的真实耗时
直接用 microtime(true) 包住调用,别信“大概”“感觉”,尤其是处理大数组或嵌套深的结构时,毫秒级差异会放大成明显卡顿。
常见错误是只测一次——冷启动、OPcache 未生效、JIT 未预热,结果偏差极大。必须循环测多次取中位数或最小值,排除系统抖动干扰。
- 用
for ($i = 0; $i 跑一批,<code>array_merge($times)后用sort()取中间几个值 - 确保数据源一致:不要在循环里动态生成新数组,先
$data = [...]固定好再复用 - 禁用 Xdebug(
ini_set('xdebug.mode', 'off')),它会让json_encode慢 3–5 倍
为什么 json_encode 在 PHP 8.1+ 突然变慢了?
不是变慢,是更严格了:PHP 8.1 默认开启 JSON_THROW_ON_ERROR 行为(但不抛异常,而是静默转失败),而你如果没显式传 flags,实际走的是兼容模式,内部多一层判断逻辑。
真正影响性能的是你传的 flags 组合。比如加了 JSON_UNESCAPED_UNICODE 对中文多字节处理更少,反而更快;但加 JSON_PRETTY_PRINT 会触发格式化遍历,耗时翻倍以上。
立即学习“PHP免费学习笔记(深入)”;
- 查当前默认行为:
var_dump(JSON_DEFAULT_DEPTH)(PHP 8.3 是 512,之前是 65535) - 深度超限不会报错,而是返回
false,但耗时仍计入——得先用json_last_error()判定是否真失败 - 大对象慎用
JSON_PARTIAL_OUTPUT_ON_ERROR,它会在出错时尝试截断输出,反而增加判断开销
json_decode 解析失败却不报错?怎么定位是哪一层崩的
根本原因:默认不启用异常模式,false 返回值被当成空数组或 0 处理,上游逻辑继续跑,直到某处 foreach 报 Invalid argument supplied for foreach() 才暴露问题。
必须主动检查 json_last_error(),且不能只看是不是 JSON_ERROR_NONE——有些错误(如 JSON_ERROR_DEPTH)在大嵌套时才触发,但返回值仍是 false。
- 解码后立刻写:
if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception(json_last_error_msg()); } - 对未知来源 JSON,加
JSON_THROW_ON_ERROR(PHP 7.3+),它让失败直接抛JsonException,堆栈能精准定位到哪行json_decode - 注意:
json_last_error()是全局状态,多线程/协程环境里可能被其他请求覆盖,务必紧挨着json_decode调用
监控线上 JSON 处理耗时,该埋点还是用扩展?
埋点够用,别急着上 ext-jsond 或 simdjson 扩展——PHP 自带 json 扩展已足够快,99% 场景瓶颈不在解析本身,而在数据组装或后续业务逻辑。
真正要监控的是「从收到原始字符串到完成解码并校验完毕」这一整段,否则你会误判:比如你以为 json_decode 慢,其实是前面 file_get_contents 读磁盘慢,或者 mb_convert_encoding 转码拖累了。
- 记录起始时间点放在接收完 HTTP body 后,而不是
$_POST或php://input读取前 - 用
error_log("json_time: " . round(($end - $start) * 1000, 2) . "ms", 4)写到 syslog,比echo或var_dump少干扰 - 别对每个请求都打全量日志,按百分比采样(如
rand(1, 100) ),避免 IO 打满
最常被忽略的是字符编码隐式转换——json_decode 要求 UTF-8,但你从数据库或旧接口拿到的是 GBK,mb_convert_encoding 那一下可能比解析本身还慢两倍。先确认输入是不是真 UTF-8,别一上来就优化 json_decode。











