PHP创建大型JSON字符串

时间:2016-05-17 14:41:35

标签: php json

我正在开发一个应用程序,用户应该看到一个包含图表的列表。应该从数据库(当前大约785行)中获取图表的数据,然后对其进行排序以形成有效的JSON字符串。对不,我试着像这样做

staging

当我尝试运行代码时,它会给出一个"致命错误:允许的内存大小为536870912字节耗尽(试图分配71个字节)"错误。我试图增加最大允许内存,只是为了看看会发生什么,但我得到了相同的结果。

有没有办法避免必须这么多循环?或者我应该从一个完全不同的方式来解决这个问题,如果是这样的话?

最终结果看起来应该是这样的

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

所有帮助将不胜感激!

4 个答案:

答案 0 :(得分:1)

您的问题不是循环次数,而是$appData数组的大小和php配置的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的变量中堆叠所有数据。

答案 1 :(得分:1)

内存问题出在&#34; for&#34;环。它可以为每个循环的$ appData添加一堆项目,而不是&#34;如果没有匹配的名称,只需添加一个。&#34;例如,如果$ appData中已有100个项目,并且$ row [&#39; name&#39;]匹配$ appData中的最后一项,那么$ appData中的最后一项之前将有99个项目添加到$ appData已更新。我敢打赌,当前代码生成的$ appData包含超过785项。

要解决内存问题,请更改&#34; for&#34;循环到这样的事情:

    $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建议的关联数组将是一个很大的加速。

答案 2 :(得分: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)."]";

答案 3 :(得分: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'];
}