json-machine通过流式解析实现恒定内存占用,解决传统json_decode因全量加载导致的内存溢出问题;它基于Generator逐项处理JSON,峰值内存与文件大小无关,实测100GB文件仅需3–5MB内存。
直接用 json_decode(file_get_contents($file)) 解析 25MB+ 的 JSON 文件,内存必然爆——这不是 PHP 版本问题,是数据规模和处理模型根本错配。
它必须把整个 JSON 字符串加载进内存,再递归构建嵌套数组/对象。25MB 原始 JSON 解码后常占 100MB+ 内存;500MB 文件基本无解。更隐蔽的是:Web SAPI 下还叠加了 max_execution_time 和输出缓冲限制,脚本可能静默中断,连错误都不报。
ini_set('memory_limit', '2G') —— 单请求吃掉 2GB 内存,高并发时 PHP-FPM 进程池直接雪崩json_last_error() 返回 JSON_ERROR_NONE 也不代表成功:若因超时被 kill,函数根本没执行完它基于生成器(Generator)做流式解析,只在内存中保留当前 JSON 项,峰值内存与文件大小无关。实测解析 100GB JSON,内存稳定在 3–5MB。
composer require halaxa/json-machine
$items = JsonMachineItems::fromFile('data.json');,然后 foreach ($items as $key => $value) 迭代/results/users):Items::fromFile('data.json', ['pointer' => '/results/users'])
Items::fromIterable(new JsonMachineLineReader('data.json'))
流式解析器不自动处理编码和结构异常,这些得前置清理:
立即学习“PHP免费学习笔记(深入)”;
$content = file_get_contents('data.json'); $content = ltrim($content, "xEFxBBxBF");,再喂给 Items::fromString()
$content = mb_convert_encoding($content, 'UTF-8', 'GBK');
json_decode() 会报 JSON_ERROR_DEPTH,但 json-machine 不受此限——它根本不预建完整树foreach 循环里用空合并操作符:$name = $user->name ?? 'unknown';
若项目不能引入第三方依赖,可用 pcrov/jsonreader(纯拉式解析器,零依赖)或手写简易状态机:
pcrov/jsonreader 安装:composer require pcrov/jsonreader;核心是 $reader->read() + $reader->value(),适合需精细控制节点遍历的场景fopen() + fgets() 逐行读,每行调 json_decode($line, null, 512, JSON_THROW_ON_ERROR) ——注意显式传 JSON_THROW_ON_ERROR 避免 silent failsubstr() 或正则硬切 JSON,结构稍复杂就崩溃真正卡住人的从来不是库选不对,而是把“大文件”当成“一个整体”来对待。只要记住:任何需要 file_get_contents() 全量加载的方案,在 25MB+ 场景下都该被标记为危险操作。