【问题标题】:PHP loop optimizationPHP循环优化
【发布时间】:2010-09-15 13:44:35
【问题描述】:

我有一个 php 方法,它使用从属性中检索的数据创建一个 HTML 表。 我最关心的是我的应用程序的性能,因为我要处理大量数据。

public function getHTML() {

    $phpObj =  json_decode($this->data); // array(object, object, object, ....);

    $table = "<table><tbody>\n";

    if (count($phpObj->query->results->row) > 0) {
        $row = $phpObj->query->results->row;

         foreach ($row as $value) {
            $table .= "<tr>\n";
            foreach ($value as $key => $val) { // concerned about loop inside loop
                $table .= "<td>" . $value->$key . "</td>"; 
            }
            $table .= "\n</tr>\n";
        }   

        $table .= "</tbody></table>";
        return $table;
    }
    else {
        return 'HTML table not created.';
    }       
}

有没有更有效的方式来遍历数组和对象而不在循环中创建循环?

【问题讨论】:

  • 我们在这里谈论多少次迭代?我没有看到任何其他方式来遍历没有循环和内部循环的二维数组。您是否对其进行了基准测试以查看它是否确实对资源造成了问题?
  • 最近的问题PHP is very slow when printing a large amount of information 的可能重复项。你必须优化你的“大量数据”,伙计,而不是检索它的循环。说,分页总是有帮助
  • @Fanis,我对 php 比较陌生,我正在创建的应用程序很大程度上依赖于 YQL 和 javascript - php 是那些禁用 javascript 的人的后备。
  • 除非您分析了这段代码并且它确实太慢了,否则您不会遇到性能问题。你有吗?

标签: php


【解决方案1】:

不要连接并返回值,而是立即回显它。不太干净,但性能会更有趣,因为字符串会立即输出到管理更有效的输出缓冲区。

循环中的循环通常是遍历二维数组的最佳方式。

【讨论】:

  • 作为折衷方案,考虑 ob_start() 和朋友。
  • 感谢您的回答,正如 Fanis 还指出的那样,我认为我无法避免二维数组中的循环内的循环。
【解决方案2】:

字符串连接是成本密集型的​​。您可以通过使用数组来减少重复字符串连接的数量:

public function getHTML() {
    $phpObj =  json_decode($this->data);
    if (count($phpObj->query->results->row) > 0) {
        $rows = array();
        foreach ($phpObj->query->results->row as $row) {
            $cells = array();
            $rows[] = "<td>" . implode("</td><td>", $row) . "</td>";
        }
        return "<table><tbody>\n<tr>\n" .
               implode("\n<tr>\n<tr>\n", $rows) .
               "\n</tr>\n</tbody></table>";
    } else {
        return 'HTML table not created.';
    }
}

您也可以使用anonymous functions(自 PHP 5.3 起可用):

public function getHTML() {
    $phpObj =  json_decode($this->data);
    if (count($phpObj->query->results->row) > 0) {
        return "<table><tbody>\n<tr>\n" .
               implode("\n<tr>\n<tr>\n", array_map(function($cells) { return "<td>".implode("</td><td>", $cells)."</td>"; }, $phpObj->query->results->row)) .
               "\n</tr>\n</tbody></table>";
    } else {
        return 'HTML table not created.';
    }
}

【讨论】:

  • 哦,不。我不敢相信自己的眼睛
  • Gumbo,在这样一个与性能相关的问题中在黑暗中拍摄是一种罪过。阅读戈登的评论。字符串连接是最后可能花费任何代价的事情。现实生活中的应用程序从未经历过仅因字符串连接而造成的任何性能损失。我没有提到 PHP 在使用大数组时遇到的问题,因为比较这两种方法不是我的重点,而是说如果没有分析和发现瓶颈,这一切都是在黑暗中拍摄的。
  • @Col。弹片:字符串连接昂贵的。使用 1000 行数组 (range("a", "z")) 重复这些算法 1000 次的快速基准测试显示了 16.53284383 秒(原始代码)与 4.68570399 秒(我的第一个提议)与 4.79068303(我的第二个提议)的结果。
  • @Gumbo 阅读 PHP 源代码,implode 是作为字符串连接序列实现的。一开始我不相信。
  • @Mike Axiak:当然,在某些方面需要连接字符串。但是机器代码级别的字符串连接仍然比 PHP 代码级别更快。
【解决方案3】:

更新 Shrapnel 上校正确地指出,奇怪的是,字符串连接实际上在 php 中相对较快。

正如文森特所说,不要运行一堆串联,那会杀了你。您有两个选项可以加快脚本速度:

  1. 立即回显。
  2. 将您的行存储在一个数组中,并在最后加入该数组。

两个例子:

<?php

$mylines = array();
foreach ($row as $value) {
    $mylines[] = "<tr>\n";
    foreach ($value as $key => $val) { // concerned about loop inside loop
        $mylines[] = "<td>" . $value->$key . "</td>"; 
    }
    $mylines[] = "\n</tr>\n";
}
return implode('', $mylines);

【讨论】:

  • 你真的确定是串联会杀死任何东西吗?你真的确定数组操作会更快吗?
  • 你是对的。在 Perl 或 Python 中就是这种情况,我错误地认为 PHP 的 implode 会进行智能字符串缓冲。显然 implode() 非常慢。
  • 令人惊讶的是,元素大小为 20 字节,implode 仍然比 concat 快 2 倍。
【解决方案4】:

您可以将 HTML 构建移动到前端,并通过 AJAX 和 javascript 将 JSON 数据发送给用户。

这也可以让您一次只发送数据片段(取决于您的 html 布局),因此可以在需要时动态轮询它们(例如 google/bing 图像搜索)。

我知道我没有直接回答这个问题。那是因为你拥有的代码可能是最快的(在 PHP 中),没有做一些愚蠢的小优化,只会使代码更难阅读/维护(可能只会节省几个 %)。

编辑:再次查看后,我敢打赌您的代码实际上只是从 JSON 中的外部源轮询数据。您可以通过让前端 javascript 执行 HTTP 命中并处理那里的数据来完全删除此代码。这完全消除了运行此 PHP 代码的需要

编辑 2:在阅读了您关于这是禁用 javascript 的后备的评论后,我查看了您当前正在执行的代码。它似乎可以翻译成implode

//declared this functions somewhere
function tr_build( $row_value )
{
    $tablerow .= "<tr>\n";
    if( $row_value ) {
        $tablerow .= "<td>".implode( "</td><td>", $row_value )."</td>";
    }
    $tablerow .= "\n</tr>\n";
    return $tablerow;
}

//this replaces the double loop
if( $row ) {
    $tablerows = "<tr>\n".implode( "\n</tr>\n<tr>\n", array_map( "tr_build", $row ) )."\n</tr>\n"
} else {
    $tablerows = "";
}

【讨论】:

  • 用 PHP 生成 HTML 比 Javascript 更安全。如果你做的一切都是 JS,你暴露了原始的 JSON 源和生成算法,这两者都可以在某些方面被利用。
  • @Vincent 在这种情况下,他想要做的就是将 JSON blob 转换为 HTML,没有什么是“暴露”的。唯一改变的是数据转换为用户可查看的格式。
  • @Vincent 你在开玩笑吗?这只是数据,它可以以任何形式被利用。您认为 XML 是同样危险的格式吗?
【解决方案5】:

你为什么要为此烦恼?

        $table .= "<tr>\n";
        foreach ($value as $key => $val) { // concerned about loop inside loop
            $table .= "<td>" . $value->$key . "</td>"; 
        }
        $table .= "\n</tr>\n";

你从来没有真正使用过$val,那为什么还要有这个循环呢?

        $table .= "<table><td>";
        $table .= implode("</td><td>", array_keys($value));
        $table .= "</td></table>";

【讨论】:

  • 实际上,implode 只是这种循环的语法糖。差别不大。虽然看起来更整洁
  • 非常正确,就像基本级别的 array_keys 一样,但我希望(真的希望)内置函数比在 PHP 中使用循环操作更优化。
猜你喜欢
  • 1970-01-01
  • 2012-03-10
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多