将JSON字符串转换为数组WITHOUT json_decode

时间:2015-02-27 19:33:42

标签: php arrays json preg-match-all preg-split

我在共享服务器上使用PHP通过API返回外部站点,该API返回包含2级数据的JSON(级别1:执行者和级别2:执行者中的类别数组)。我想将此转换为多维关联数组,不使用json_decode函数(它使用了太多内存用于此用途!!!)

JSON数据示例:

[
{
    "performerId": 99999,
    "name": " Any performer name",
    "category": {
        "categoryId": 99,
        "name": "Some category name",
        "eventType": "Category Event"
    },
    "eventType": "Performer Event",
    "url": "http://www.novalidsite.com/something/performerspage.html",
    "priority": 0
},
{
    "performerId": 88888,
    "name": " Second performer name",
    "category": {
        "categoryId": 88,
        "name": "Second Category name",
        "eventType": "Category Event 2"
    },
    "eventType": "Performer Event 2",
    "url": "http://www.novalidsite.com/somethingelse/performerspage2.html",
    "priority": 7
}
]

我尝试使用substr并删除“[”和“]”。

然后执行了电话:

preg_match_all('/\{([^}]+)\}/', $input, $matches);

这为我提供了每行的字符串BUT在类别数据的尾随“}”之后截断。

如何使用类似preg_split,preg_match_all等的方式返回数据的完整行数。对整个JSON字符串上的json_decode等重度调用进行INSTEAD?

一旦我有正确识别每一行的数组,我就可以在该字符串上执行json_decode而不会使共享服务器上的内存过载。


对于那些想了解更多有关json_decode用法导致错误的详细信息:

$aryPerformersfile[ ] = file_get_contents('https://subdomain.domain.com/dir/getresults?id=1234');
$aryPerformers = $aryPerformersfile[0];
unset($aryPerformersfile);
$mytmpvar = json_decode($aryPerformers);
print_r($mytmpvar);
exit;

2 个答案:

答案 0 :(得分:3)

如果内存量有限,您可以将数据作为流读取并一次解析一个JSON,而不是一次解析所有内容。

getresults.json:

[
    {
        "performerId": 99999,
        "name": " Any performer name",
        "category": {
            "categoryId": 99,
            "name": "Some category name",
            "eventType": "Category Event"
        },
        "eventType": "Performer Event",
        "url": "http://www.novalidsite.com/something/performerspage.html",
        "priority": 0
    },
    {
        "performerId": 88888,
        "name": " Second performer name",
        "category": {
            "categoryId": 88,
            "name": "Second Category name",
            "eventType": "Category Event 2"
        },
        "eventType": "Performer Event 2",
        "url": "http://www.novalidsite.com/somethingelse/performerspage2.html",
        "priority": 7
    }
]

PHP:

$stream = fopen('getresults.json', 'rb');

// Read one character at a time from $stream until
// $count number of $char characters is read
function readUpTo($stream, $char, $count)
{
    $str = '';
    $foundCount = 0;
    while (!feof($stream)) {
        $readChar = stream_get_contents($stream, 1);

        $str .= $readChar;
        if ($readChar == $char && ++$foundCount == $count)
            return $str;
    }
    return false;
}

// Read one JSON performer object
function readOneJsonPerformer($stream)
{
    if ($json = readUpTo($stream, '{', 1))
        return '{' . readUpTo($stream, '}', 2);
    return false;
}

while ($json = readOneJsonPerformer($stream)) {
    $performer = json_decode($json);

    echo 'Performer with ID ' . $performer->performerId
        . ' has category ' . $performer->category->name, PHP_EOL;
}
fclose($stream);

输出:

Performer with ID 99999 has category Some category name
Performer with ID 88888 has category Second Category name

当然,通过使用缓冲区来实现更快的读取,可以改进此代码,考虑到字符串值本身可能包含{}字符等。

答案 1 :(得分:0)

这里有两个选项,它们都不包括你编写自己的解码器;不要过度复杂化解决方案。

1)减小正在解码的json的大小,或 2)增加服务器上允许的内存。

第一个选项需要访问正在创建的json。根据您是否是最初创建json的人,这可能会也可能不会。最简单的方法是unset()任何无用的数据。例如,可能有一些您不需要的调试信息,因此您可以对无用数据执行unset($json_array['debug']);http://php.net/manual/en/function.unset.php

第二个选项要求您可以访问服务器上的php.ini文件。您需要找到memory_limit = 128M之类的行,并使128M部分变大。尝试增加此值以使文件中已有的值加倍(因此在这种情况下为256M)。这可能无法解决您的问题,因为大型json数据仍然可能是您问题的核心;这只能为低效的代码提供解决方法。