开发者

PHP loop optimization

I have a php method that creates an HTML table with data it retrieves from a property. My biggest concern is the performance of my application because I deal with a large amount of data.

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.';
    }       
}

Is there a more efficient way of traversing through the array and objects without creating a loop inside a开发者_如何学C loop?


Don't concatenate and return the value, echo it immediately instead. Less clean but the performance will be much more interesting since the strings are immediately outputed to the output buffer which is managed more efficiently.

A loop inside a loop is often the best way to traverse a two-dimensional array.


String concatenation is cost-intensive. You could reduce the number of repetitive string concatenations by using arrays:

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.';
    }
}

You could also use anonymous functions (available since 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.';
    }
}


UPDATE Col. Shrapnel correctly stated that, oddly, string concatenation is actually relatively fast in php.

As Vincent said, don't run a bunch of concatenations, that's killing you. You have two options to speed up your script:

  1. Echo immediately.
  2. Store your lines in a an array, and join the array at the end.

Example of two:

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


You could move the HTML building into the frontend and ship the JSON data to the user via AJAX and javascript.

This could also allow your to only ship pieces of the data at a time (depending on your html layout), so they could be dynamically polled when needed (like google/bing image search).

I know I didn't answer the question directly. That is because the code you have is probably the fastest it can be done (in PHP) w/o doing silly little optimizations that would only make the code harder to read/maintain (probably only save a few % anyway).

EDIT: after looking at it again, I bet your code is actually just polling the data from an external source in JSON. You could probably remove this code completely by having the frontend javascript do the HTTP hit and deal with the data there. This removes the need for this PHP code to run at all.

EDIT 2: after reading your comment about this being a fall back for javascript being disabled, I looked at the code your currently doing. It appears to be translatable into 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 = "";
}


Why are you bothering with this?

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

You never actually use $val so why have this loop at all?

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜