Alternative to concatenating $return string to build HTML table

1.5k views Asked by At

I have a program in which a function returns a rather large HTML table using a series of dot equal sign concatenation assignments like this:

function callme() {
    $return = '';
    $return .= '<table>';
    foreach ($foo as $bar => $bar){
      $return .= '<tr><td style="css">bla bla bla'.$bar.'</td>';
      $return .= '<td>more stuff, modal buttons</td></tr>';
      $return .= 'etc etc etc...';
    }
    $return .= '</table>';
return $return
}

I'd like to find a less error prone, WET way of handling this and not sure if it should be using an array that I add each item to and implode/join, maybe using an object would make sense.

I've googled around a bit without a whole lot of luck and would love some input from the SO community.

EDIT:

Not sure if there's any way of making this post On-Topic as I can see now that there's really no way to select a correct solution, so since it's too late to delete it (and maybe post to the php mailing list as would have been more appropriate), I'll at least try and make it more useful.

Spent 30 minutes debugging a script in which a table that was being generate by concatenating the HTML, text and variable components using the "dot equals" method, and where a bug was causing every text element to be rendered as an anchor (<a>some text</a>). After removing all the javascript, which I expected was somehow generating the anchor tags in the DOM elements, tracked down the bug in the following line:

$return .= '<br/><div id="visitMBO" class="btn visitMBO" style="display:none"><a href="'.$eventLinkURL.'" target="_blank">Manage on MindBody Site<a/></div>';

Error is at the end of the line: <a/>. Whoops.

It's a fairly long table including lots of CSS classes and ids used by javascript, as well as many variables so there's tons of single quotes, double quotes and dots all over the place. Now I want to be able to render different variations on it based on user input and having either multiple version of it separated by test clauses or having tests throughout it will probably be even worse.

Asking about an HTML table generator class would have been more appropriate, but also off-topic. Options there include the fairly light-weight: htmlgen, the more robust Cellbrush and DynaWeb's Table Class which is also fairly light-weight as far as I can tell.

As one answer below states, .= is a reasonable approach if the table's not too too complex, and if I had merely kept each line to a shorter length the problem would have been more visible. As it was, the anchor's start tag was practically falling off the edge of the page.

Noted in answers below (with links) other options for separating logic, markup and data would be using a template engine or using php's DOM class (tutorial). Heredoc would also clean up some of the redundancy and multiple quotation marks a bit.

3

There are 3 answers

0
Matt Urtnowski On

If you want a classful way to do this, check out DomDocument http://www.php.net/manual/en/class.domdocument.php

You can use it to construct HTML in a very structured way. However, given this example I don't think their is necessarily a right way to solve the issue. You should find a style that you are comfortable with and makes sense to you and your team; that's the best way to help avoid buggy code.

For me, I usually just write code using the .= exactly how you are so long as the code is fairly small. It's a very easy to read method. If I can glance at a piece of code and understand it without thinking generally its ok code.

1
flyingL123 On

One option would be to use a templating engine rather than putting your HTML code directly in your PHP function. An example is mustache.

This will allow you to construct your HTML in a separate file and pass data to it.

Your template file might look something like this:

<table>
    {{# foo }}
        <tr>
            <td>{{ bar }}</td>
        </tr>
    {{/ foo }}
</table>

And you would then get your HTML string from it like this:

$m = new Mustache_Engine(array(
    'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__) . '/templates'),
));

$m->render('table_template', array('foo' => $foo));
0
Drakes On

There are many ways to do things with strings in PHP. It's worth noting that if you have a large contiguous block of HTML that you want to want to concatenate with a string, one helpful way to do so without quotes is with Heredoc. For example

function callme(&$rows) {
    $return = '<table>' . PHP_EOL;
    foreach ($rows as $row){
      // Start a heredoc-delimited string
      $return .= <<<EOD
      <tr>
         <td>Movie name: "$row[0]"</td>
         <td>Review: $row[1]</td>
         <td>IMDB rating: $row[2]</td>
         <td>Summary: "$row[0]" was $row[1] with a rating of $row[2]</td>
      </tr>
EOD;
// End a heredoc-delimited string (must be on its own line)
    }
    return $return . PHP_EOL . '</table>';
}

$arr = array(array("Fast 7", "awesome", "7.6"), array("Glitter", "horrible", "2.1"));
echo callme($arr);

Result:

<table>
      <tr>
         <td>Movie name: "Fast 7"</td>
         <td>Review: awesome</td>
         <td>IMDB rating: 7.6</td>
         <td>Summary: "Fast 7" was awesome with a rating of 7.6</td>
      </tr>      <tr>
         <td>Movie name: "Glitter"</td>
         <td>Review: horrible</td>
         <td>IMDB rating: 2.1</td>
         <td>Summary: "Glitter" was horrible with a rating of 2.1</td>
      </tr>
</table>