2016-05-17 62 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

內存問題出現在「for」循環中。它可以在每個循環中向$ appData添加一堆項目,而不是「如果沒有匹配的名稱,則只添加一項」。例如,如果$ appData已經有100個項目,並且$ row ['name']匹配$ appData中的最後一個項目,那麼在$ appData中的最後一個項目被更新之前,99個項目將被添加到$ appData。我敢打賭,目前的代碼正在生成一個$ appData,其中有超過785個項目。

要解決內存問題,改變「for」循環來是這樣的:

$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

你的問題不是循環的數量,而是你的php配置的$appData數組的大小和memory_limit的值。

如果無法縮小傳遞的數據大小,則必須增加memory_limit值。但在增加此值時要小心,因爲它是您的服務器將執行的每個正在運行的php腳本的值。我會建議分頁或發送到每個循環的輸出緩衝區。

如果你需要例子的代碼,只是要求它。

分頁意味着您的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']; 
}