2016-05-17 3 views
0

Ich arbeite an einer Anwendung, wo der Benutzer eine Liste mit Diagrammen sehen sollte. Die Daten für die Diagramme sollten aus einer Datenbank abgerufen werden (die derzeit ungefähr 785 Zeilen zählt) und dann sortiert werden, um eine gültige JSON-Zeichenfolge zu bilden. Recht nicht, dass ich versuche, es zu tun, wie diesPHP erstellt große JSON-String

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); 

Wenn ich versuche, den Code auszuführen wird es einen geben „Fatal error: Erlaubt Speichergröße von 536.870.912 Bytes erschöpft (versucht, 71 Bytes zuzuteilen)“ Fehler. Ich habe versucht, den maximal zulässigen Speicher zu erhöhen, nur um zu sehen, was passieren würde, aber ich habe das gleiche Ergebnis.

Gibt es eine Möglichkeit, so viele Schleifen zu vermeiden? Oder sollte ich das ganz anders angehen, und wenn ja, welches?

Das Endergebnis sollte so etwas wie dieses

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

Alle Hilfe würde geschätzt aussehen!

+0

Mögliche Duplikate von [Erlaubte Speichergröße von 33554432 Bytes erschöpft (versucht, 43148176 Bytes zuzuweisen) in PHP] (http://stackoverflow.com/questions/415801/allowed-memory-size-of-33554432-bytes-exhausted -tried-to-allocate-43148176-byte) –

Antwort

1

Das Speicherproblem ist in der "for" -Schleife. Es kann eine Menge von Elementen zu $ ​​appData pro Schleife hinzugefügt werden, anstatt "nur eine, wenn es keinen passenden Namen gibt". Wenn zum Beispiel $ appData bereits 100 Elemente enthält und $ row ['name'] mit dem letzten Element in $ appData übereinstimmt, werden 99 Elemente zu $ ​​appData hinzugefügt, bevor das letzte Element in $ appData aktualisiert wird. Ich wette, der aktuelle Code generiert $ appData mit mehr als 785 Elementen.

das Speicherproblem zu beheben, die „für“ Schleife zu so etwas wie dies ändern:

$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"]) 
     ); 
    } 

Auf einer Effizienz Note, indem ein assoziatives Array, wie durch maximkou vorgeschlagen wird eine große Beschleunigung sein.

+0

Funktioniert wie ein Charme, vielen Dank! :) –

1

Ihr Problem ist nicht die Anzahl der Schleifen, sondern die Größe Ihres $appData Arrays und der memory_limit Wert Ihrer PHP-Konfiguration.

Wenn Sie die Größe der übergebenen Daten nicht verkleinern können, müssen Sie den Wert für memory_limit erhöhen. Aber seien Sie vorsichtig, wenn Sie diesen Wert erhöhen, da dies der Wert für jedes laufende PHP-Skript ist, das Ihr Server ausführt. Ich würde empfehlen, zu paginieren oder an den Ausgangspuffer für jede Schleife zu senden.

Wenn Sie ein Beispiel für Code benötigen, fragen Sie einfach danach.

Paginierung bedeutet, dass Ihre JavaScript-Seite X-mal das PHP-Skript aufrufen wird, um N Zeilen jedes Mal abzurufen, bis die PHP-Skripts es nicht mehr erlauben. Deshalb müssen Sie ein Array zurück, wie:

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

// Or 

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

Oder auf jeder Schleife an den Ausgabepuffer senden und Speicher freigeben:

$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 ']'; 

Auf diese Weise können nicht alle Daten in PHP-Variablen stapeln.

+0

Wenn Sie ein Beispiel haben, wäre das großartig! –

+0

Ich habe meine Antwort aktualisiert. – JesusTheHun

0

Indexieren Sie Ihr Array von $row['name']. Dies vereinfacht Ihren Code. Arrays in PHP ordnen viel Speicher zu, also kodieren Sie verschachtelte Daten nach Zeilen. Oder versuchen Sie SplFixedArray zu verwenden, wenn Sie die Arraygröße kennen.

Try this:

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

Dies sollte exakt die gleichen Ergebnisse schaffen (tho nicht getestet) und verwendet eine Karte Array und array_key_exists() Extraschleifen zu vermeiden. Dies geschieht in einer einzigen Schleife.

$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']; 
} 
Verwandte Themen