PHP-json_encode一个生成器对象(使用yield) [英] PHP - json_encode a generator object (using yield)

查看:113
本文介绍了PHP-json_encode一个生成器对象(使用yield)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很大的PHP(5.6)数组,它是动态生成的,我想将其转换为JSON.问题是该数组太大,无法容纳在内存中-尝试处理该数组时,我收到一个致命错误(内存耗尽).因此我发现,使用生成器,内存问题将消失.

I have a very large array in PHP (5.6), generated dynamically, which I want to convert to JSON. The problem is that the array is too large that it doesn't fit in memory - I get a fatal error when I try to process it (exhausted memory). So I figured out that, using generators, the memory problem will disappear.

这是我到目前为止尝试过的代码(这个简化的示例显然不会产生内存错误):

This is the code I've tried so far (this reduced example obvisously doesn't produce the memory error):

<?php 
function arrayGenerator()// new way using generators
{
    for ($i = 0; $i < 100; $i++) {
        yield $i;
    }
}

function getArray()// old way, generating and returning the full array
{
    $array = [];
    for ($i = 0; $i < 100; $i++) {
        $array[] = $i;
    }
    return $array;
}

$object = [
    'id' => 'foo',
    'type' => 'blah',
    'data' => getArray(),
    'gen'  => arrayGenerator(),
];

echo json_encode($object);

但是PHP似乎不对生成器中的值进行JSON编码.这是我从previuos脚本获得的输出:

But PHP seems to not JSON-encode the values from the generator. This is the output I get from the previuos script:

{
    "id": "foo",
    "type": "blah",
    "data": [// old way - OK
        0,
        1,
        2,
        3,
        //...
    ],
    "gen": {}// using generator - empty object!
}

是否可以在调用json_encode之前对生成器生成的数组进行JSON编码而不生成完整序列?

Is it possible to JSON-encode an array produced by a generator without generating the full sequence before I call to json_encode?

推荐答案

不幸的是,json_encode无法从生成器函数生成结果.使用iterator_to_array仍会尝试创建整个数组,这仍然会导致内存问题.

Unfortunately, json_encode cannot generate a result from a generator function. Using iterator_to_array will still try to create the whole array, which will still cause memory issues.

您将需要创建函数,该函数将从generator函数生成json字符串.这是一个看起来如何的示例:

You will need to create your function that will generate the json string from the generator function. Here's an example of how that could look:

function json_encode_generator(callable $generator) {
    $result = '[';

    foreach ($generator as $value) {
        $result .= json_encode($value) . ',';
    }

    return trim($result, ',') . ']';
}

它不是一次编码整个数组,而是一次只编码一个对象,然后将结果连接成一个字符串.

Instead of encoding the whole array at once, it encodes only one object at a time and concatenates the results into one string.

以上示例仅涉及对数组进行编码,但是可以轻松地扩展为递归编码整个对象.

The above example only takes care of encoding an array, but it can be easily extended to recursively encoding whole objects.

如果创建的字符串仍然太大而无法容纳在内存中,那么您唯一剩下的选择就是直接使用输出流.这是这样的样子:

If the created string is still too big to fit in the memory, then your only remaining option is to directly use an output stream. Here's how that could look:

function json_encode_generator(callable $generator, $outputStream) {
    fwrite($outputStream, '[');

    foreach ($generator as $key => $value) {
        if ($key != 0) {
            fwrite($outputStream, ','); 
        }

        fwrite($outputStream, json_encode($value));
    }

    fwrite($outputStream, ']');
}

如您所见,唯一的区别是我们现在使用fwrite而不是串联字符串来写入传递的流,并且我们还需要以其他方式处理尾随逗号.

As you can see, the only difference is that we now use fwrite to write to the passed in stream instead of concatenating strings, and we also need to take care of the trailing comma in a different way.

这篇关于PHP-json_encode一个生成器对象(使用yield)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆