Преобразование строки JSON в массив БЕЗ json_decode

Я использую PHP на общем сервере для доступа к внешнему сайту через API, который возвращает JSON, содержащий 2 уровня данных (уровень 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);

Это дает мне строку для каждой строки, НО усекается после завершающего «}» данных категории.

Как я могу вернуть ПОЛНУЮ СТРОКУ данных КАК МАССИВ, используя что-то вроде preg_split, preg_match_all и т. д. ВМЕСТО сложных вызовов, таких как json_decode, в общей строке JSON?

Как только у меня будет массив с правильной идентификацией каждой строки, Я МОГУ выполнить 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;

person Beach Carolina    schedule 27.02.2015    source источник
comment
Может ли эта ссылка stackoverflow.com/questions/2583472/regex-to-validate -json быть полезным?   -  person crrad    schedule 27.02.2015
comment
Таким образом, вместо использования json_decode вы, несомненно, вызываете менее эффективный обходной путь. Ага. Это пойдет плавно. @AbraCadaver проверьте phantomJS   -  person James Spence    schedule 27.02.2015
comment
как он использует слишком много памяти? Можете ли вы показать нам, как это использует слишком много, каково ваше определение слишком много? я предполагаю, что функция не слишком много использует, это то, что вы неправильно собираете мусор с помощью unset(), или вам нужно увеличить выделение памяти в вашем приложении.   -  person cmorrissey    schedule 27.02.2015
comment
Мне очень интересно, как вы рассчитали, что json_decode использует too much memory? насколько велик ваш json sring? сколько json_decode занимает в вашем случае? какой инструмент вы использовали для масштабирования использования памяти?   -  person Alex    schedule 27.02.2015
comment
Спасибо за насмешку без доказательств. Это так ценится! На веб-сайте, который в настоящее время работает под управлением Wordpress (PHP и MySQL) на виртуальном хостинге. Я делаю вызов API, который возвращает содержимое JSON в переменную. Когда я вызываю json_decode для переменной, я получаю следующую ошибку: Неустранимая ошибка PHP: допустимый размер памяти 134217728 байт исчерпан (попытка выделить 10 байт) в /home/mysite/public_html/subdir/myfile.php в строке 3.   -  person Beach Carolina    schedule 27.02.2015
comment
так что, может быть, ваш код WP не оптимизирован? Вы понимаете, что json_decode — это последняя команда, которая была отправлена ​​перед ошибкой и пыталась выделить 10 байт? ;-) доказывает ли это, что json_decode злоупотребляет памятью?   -  person Alex    schedule 27.02.2015
comment
На самом деле ошибка в строке 4. Моя ошибка.   -  person Beach Carolina    schedule 27.02.2015
comment
Увеличьте php memory_limit. preg_match_all по-прежнему будет загружать все совпадения в память, поэтому вы, вероятно, столкнетесь с той же проблемой. Кроме того, если данные, отправляемые API, слишком велики, и вы можете их контролировать, рассмотрите возможность смещения и ограничения.   -  person MegaAppBear    schedule 27.02.2015
comment
Мой сайт работает на сервере. Я ДОЛЖЕН запустить этот код в той же учетной записи на этом сервере. json_decode вызывает ошибку памяти. Я могу запустить preg_match_all и/или preg_split для переменной просто отлично!   -  person Beach Carolina    schedule 27.02.2015
comment
Дело в том, что почти ВСЯ разрешенная память используется ДО вызова, который генерирует эту ошибку.   -  person AbraCadaver    schedule 27.02.2015
comment
не могли бы вы сделать var_dump($aryPerformers); exit(); перед json_decode? какого размера твоя струна? можно ли его включить в ваш пост? есть что-то действительно личное?   -  person Alex    schedule 27.02.2015
comment
Проблема здесь, скорее всего, в размере данных того, что вы пытаетесь декодировать. Реализация вашего собственного декодирования не решит вашу проблему.   -  person Siphon    schedule 27.02.2015
comment
@BeachCarolina это единственный сайт, использующий этот сервер? Ваш WP работает хорошо с 3 месяцев? 6 месяцев несколько лет? у вас есть панель управления для проверки использования памяти, даже если на вашем сайте нет посетителей?   -  person Alex    schedule 27.02.2015


Ответы (2)


Если у вас ограниченный объем памяти, вы можете считывать данные как поток и анализировать JSON по частям вместо того, чтобы анализировать все сразу.

получить результаты.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

Этот код, конечно, можно улучшить, используя буфер для более быстрого чтения, примите во внимание, что строковые значения могут сами включать символы { и } и т. д.

person mhall    schedule 28.02.2015
comment
Спасибо @mhall! очень признателен - person Beach Carolina; 02.03.2015
comment
Это очень помогло мне. Спасибо! Для другого использования этого обязательно отрегулируйте параметр $count в соответствии со сколькими закрывающими скобками вы работаете. - person Tony Paternite; 11.10.2016

Здесь у вас есть два варианта, и ни один из них не включает в себя написание собственного декодера; не усложняйте решение ненужным обходным путем.

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 все еще могут быть ядром вашей проблемы; это обеспечивает обходной путь только для неэффективного кода.

person Siphon    schedule 27.02.2015
comment
Также стоит отметить, что проблема может быть не связана с данными json. Проблема может быть вызвана большой переменной, которая может быть вызвана до того, как произойдет декодирование, что в данном случае делает декодирование соломинкой, которая сломала хребет верблюду. - person Siphon; 27.02.2015