5

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 loop?

4
  • 2
    How many iterations are we talking about here? I don't see any other way to traverse the 2d array without loops and inside loops. Have you benchmarked it to see if it does indeed pose a problem with resources? Commented Sep 15, 2010 at 13:47
  • possible duplicate of the very recent question PHP is very slow when printing a large amount of information. You have to optimize your "large amount of data", dude, not a loop that retrieving it. Say, pagination always helps Commented Sep 15, 2010 at 13:49
  • @Fanis, I'm relatively new to php, and the application that i am creating largely relies on YQL and javascript - php is a fall back for those who disable javascript. Commented Sep 15, 2010 at 13:54
  • 3
    Unless you profiled this code and it is indeed too slow, you do not have a performance issue. Did you? Commented Sep 15, 2010 at 14:01

5 Answers 5

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

As a compromise, consider ob_start() and friends.
Thanks for your answer, as Fanis also pointed out i think there no way i can avoid a loop inside a loop in a two-dimensional arrays.
2

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

8 Comments

Oh no. I can't believe my eyes
Gumbo, it's a sin to shoot in the dark in such a performance related questions. Read Gordon's comment. And string concatenation is the last thing that may cost anything. No real life application ever experienced any performance hit from mere string concatenation. I am not mention problems PHP have with big arrays, because it's not my point to compare these 2 methods but to say that without profiling and finding a bottleneck all this is shooting in the dark.
@Col. Shrapnel: String concatenation is expensive. A quick benchmark of repeating these algorithms 1000 times with an array of 1000 rows of arrays (range("a", "z")) showed the results of 16.53284383 seconds (original code) vs. 4.68570399 seconds (my first proposal) vs. 4.79068303 (my second proposal).
@Gumbo Read the PHP source, implode is implemented as a sequence of string concatenations. I didn't believe it at first.
@Mike Axiak: Sure, in some way the strings need to be concatenated. But string concatenation on machine code level is still faster than on PHP code level.
|
1

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

3 Comments

Are you really sure that it's concatenations that is killing anything? Are you really sure that array operations would be faster?
you're right. In Perl or Python this would be the case, and I incorrectly assumed PHP's implode does intelligent string buffering. Apparently implode() is extremely slow.
Surprisingly, with element size of 20 bytes, implode is still 2 times faster than concat.
0

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 = "";
}

3 Comments

It is more secure to generate the HTML in PHP instead of Javascript. If you do everything JS, you expose the original JSON source and the generation algorithm, which can both be exploited in some ways.
@Vincent In this case all he wants to do is turn a JSON blob into HTML, there's nothing that's "exposed". The only thing that changes is where the data is turned into a format viewable by the user.
@Vincent you kidding? That's just data and it can be exploited in any form. Is XML is the same dangerous format in your opinion?
0

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

2 Comments

actually, implode is just a syntax sugar for such a loop. makes not a big difference. Although looks way more neat
Very true, as is array_keys at the base level, but I'm hoping (really hoping) that the builtin functions operate more optimally than doing it in PHP with a loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.