2016-05-17 61 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']; 
}