2016-05-17 6 views
0

Я работаю над приложением, где пользователь должен увидеть список с диаграммами. Данные для диаграмм следует извлекать из базы данных (которая в настоящее время насчитывает около 785 строк), а затем сортируются для формирования правильной строки JSON. Право не я стараюсь делать это как этотPHP, создающий большую строку JSON

while($row = $res->fetch_assoc()) { 
    if(count($appData) == 0){ 
     $appData[] = array(
      "name" => $row["name"], 
      "date" => array($row["date"]), 
      "android" => array($row["android_count"]), 
      "ios" => array($row["apple_count"]) 
     ); 
    }else { 
     for($i = 0; $i < count($appData); $i++) { 
      if($appData[$i]["name"] == $row["name"]){ 
       $appData[$i]["date"][] = $row["date"]; 
       $appData[$i]["android"][] = $row["android_count"]; 
       $appData[$i]["ios"][] = $row["apple_count"]; 
      }else { 
       $appData[] = array(
        "name" => $row["name"], 
        "date" => array($row["date"]), 
        "android" => array($row["android_count"]), 
        "ios" => array($row["apple_count"]) 
       ); 
      } 
     } 
    } 
} 
echo json_encode($appData); 

Когда я пытаюсь запустить код это даст «Фатальная ошибка: Разрешены памяти размером 536870912 байт исчерпаны (пытались выделить 71 байт)» ошибка. Я пытался увеличить максимально допустимую память, просто чтобы увидеть, что произойдет, но я получил тот же результат.

Есть ли способ избежать необходимости делать столько циклов? Или я должен подходить к этому совершенно по-другому, и если да, то какой?

Конечный результат должен выглядеть как этот

[{"name":"Some name", "date":["2016-05-09", "2016-05-10", "2016-05-11"], "android":["3", "1", "8"], "ios":["4", "7", "5"]},...] 

Вся помощь будет оценен по достоинству!

+0

Возможный дубликат [Разрешенный объем памяти 33554432 байт исчерпан (пытался выделить 43148176 байт) в php] (http://stackoverflow.com/questions/415801/allowed-memory-size-of-33554432-bytes-exhausted -tried-to-allocate-43148176-byte) –

ответ

1

Проблема с памятью в цикле «для». Он может добавлять кучу элементов в $ appData за цикл, а не «только один, если нет соответствующего имени». Например, если $ appData уже содержит 100 элементов, а $ row ['name'] соответствует последнему элементу в $ appData, тогда 99 элементов будут добавлены в $ appData до того, как последний элемент в $ appData будет обновлен. Уверен, что текущий код генерирует $ appData с более чем 785 элементами.

Чтобы устранить проблему памяти, изменить «для» петли на что-то вроде этого:

$matchFound = false; 
    for($i = 0; $i < count($appData); $i++) { 
     if($appData[$i]["name"] == $row["name"]){ 
      $appData[$i]["date"][] = $row["date"]; 
      $appData[$i]["android"][] = $row["android_count"]; 
      $appData[$i]["ios"][] = $row["apple_count"]; 
      $matchFound = true; 
      break; 
     } 
    } 
    if (!$matchFound) { 
     $appData[] = array(
      "name" => $row["name"], 
      "date" => array($row["date"]), 
      "android" => array($row["android_count"]), 
      "ios" => array($row["apple_count"]) 
     ); 
    } 

На ноты, эффективность, используя ассоциативный массив как предложено maximkou будет большой убыстрение.

+0

Работает как очарование, большое спасибо! :) –

1

Ваша проблема заключается не в количестве циклов, а в размере вашего массива $appData и значении memory_limit вашей конфигурации php.

Если вы не можете уменьшить размер передаваемых данных, вы должны увеличить значение memory_limit. Но будьте осторожны, увеличивая это значение, так как это значение для каждого запущенного php-скрипта, который будет выполнять ваш сервер. Я бы рекомендовал разбивать страницы или отправлять их в выходной буфер для каждого цикла.

Если вам нужен пример кода, просто попросите его.

Pagination означает, что ваша страница javascript вызовет X раз PHP-скрипт для извлечения N строк каждый раз, пока скрипты PHP больше не позволят. Поэтому вы должны возвращать массив, такие как:

return array(
    'nextPage' => 2, // More data available on this page 
    'data' => $json 
); 

// Or 

return array(
    'nextPage' => null, // No more data available 
    'data' => $json 
); 

Или отправить в выходной буфер на каждом цикле и освободить память:

$first = true; 
echo '['; 

while($row = $res->fetch_assoc()) { 

    if(!$first) { 
     echo ','; 
    } else { 
     $first = false; 
    } 

    // some logic 
    $row_data = array(...); 

    echo json_encode($row_data); 
} 

echo ']'; 

Таким образом, вы не складывают все данные в переменных PHP.

+0

Если у вас есть пример, вокруг, это было бы здорово! –

+0

Я обновил свой ответ. – JesusTheHun

0

Индекс вашего массива $row['name']. Это сильно упростит ваш код. Массивы в php выделяют много памяти, поэтому кодируют вложенные данные по ряду. Или попробуйте использовать SplFixedArray, если вы знаете размер массива результата.

Попробуйте это:

while($row = $res->fetch_assoc()) { 
    $appData[ $row["name"] ] = json_encode(array(
     "name" => $row["name"], 
     "date" => array($row["date"]), 
     "android" => array($row["android_count"]), 
     "ios" => array($row["apple_count"]) 
    )); 
} 
echo "[".implode(',', $appData)."]"; 
0

Это должно создать точно такие же результаты (Тхо не проверял), и использует массив карты и array_key_exists(), чтобы избежать дополнительных петель. Это делается в одном цикле.

$nameMap = array(); // hold name and keys 
while($row = $res->fetch_assoc()){ 
    $key = array_key_exists($row['name'], $nameMap) ? $nameMap[$row['name']] : count($appData); 
    $nameMap[$row['name']] = $key; 
    if(empty($appData[$key])) 
     $appData[$key] = array("name"=>$row['name'], "date"=>array(), "android"=>array(), "ios"=>array()); 
    $appData[$key]['date'][] = $row['date']; 
    $appData[$key]['android'][] = $row['android']; 
    $appData[$key]['ios'][] = $row['ios']; 
} 
Смежные вопросы