StephenJungels.com :: Open source :: Articles :: Roll Your Own HTML Templates With PHP

Roll Your Own HTML Templates With PHP

Although programmers are aware that HTML is not a programming language, after looking at a complex document in raw HTML for the first time, anyone would be certain that it is code, maybe even impenetrable code. But paradoxically, HTML becomes easier to work with when we add more of the features of a real programming language. This article will describe a simple technique that uses a few features of the PHP programming language to help make HTML code elegant, readable, and reusable. To use this technique, you will need a web server that runs PHP and basic coding skills.

Defining the problem

Consider some HTML code which defines a complex table-based page layout:

<html>
<head>
  <title>Complex table layout example</title>
  <style type="text/css">
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
      border: none;
    }
    #full { height: 100%; }
  </style>
</head>
<body>
<table bgcolor="#7777aa" width="100%" border="0" 
  cellspacing="0" cellpadding="0">
  <tr>
    <td><h1>Complex table layout example</h1></td>
  </tr>
</table>
<table width="100%" border="0" cellspacing="0" 
  cellpadding="0" id="full">
  <tr valign="top">
    <td nowrap bgcolor="#d0d0d0" width="125px">
             Menu a
<br/><a href="item1">Item 1</a>
<br/><a href="item2">Item 2</a>
<br/>
<br/>Menu b
<br/><a href="item1b">Item 1</a>
<br/><a href="item2b">Item 1</a>
    </td>
    <td>
      <p>
         This is the main content.  Alice was beginning to get
         very tired.  It was a dark and stormy night.  Call me
         Ishmael.
    </td>
    <td nowrap bgcolor="#e0e0e0" width="75px">
     <a href="http://example1.com/">Link 1</a>
<br/><a href="http://example2.com/">Link 2</a>
<br/><a href="http://example3.com/">Link 3</a>
<br/><a href="http://example4.com/">Link 4</a>
<br/><a href="http://example5.com/">Link 5</a>
<br/><a href="http://example6.com/">Link 6</a>
    </td>
  </tr>
</table>
<table width="100%" bgcolor="#d0d0d0" border="0" 
  cellspacing="0" cellpadding="0">
  <tr>
    <td><p align="center">This is the footer.  (c) 2006</td>
  </tr>
</table>
</body>
</html>

You can view the page here. Although this page is much simpler than many real-world examples, it is already unreadable. But there is a structure here, it's simply hidden by the complexity. If we can rewrite the code to reveal the hidden structure, it will instantly become more maintainable.

Searching for an HTML subroutine

One of the basic organizing features of any good programming language is the subroutine. If we had an HTML subroutine, we could use top-down design to better structure the complex table layout. So where to look? An obvious approach is to use PHP functions. For example, consider the fragment of HTML which defines the page header:

<table bgcolor="#7777aa" width="100%" border="0" 
  cellspacing="0" cellpadding="0">
  <tr>
    <td><h1>Complex table layout example</h1></td>
  </tr>
</table>

This is a good candidate for a subroutine. Using PHP functions, we could write

function header()
{
?>
  <table bgcolor="#7777aa" width="100%" border="0" 
    cellspacing="0" cellpadding="0">
    <tr>
      <td><h1>Complex table layout example</h1></td>
    </tr>
  </table>
<?php
}

However, a primary goal of this technique is readability, and all the switching back and forth between PHP and HTML hurts the readability of this code fragment. Secondly, it's poor design to write a function that echoes output immediately when called. We want a flexible technique that allows us to set up some HTML and use it whenever we need it. And finally, this technique doesn't offer an obvious way to nest subroutines.

A better approach uses another feature of PHP called "here documents." Using this technique the code would be written:

$header = <<< EOF
  <table bgcolor="#7777aa" width="100%" border="0" 
    cellspacing="0" cellpadding="0">
    <tr>
      <td><h1>Complex table layout example</h1></td>
    </tr>
  </table>
EOF;

The effect of this code fragment is to set the variable $header equal to the HTML code between the first and second "EOF". Then the variable can be reused or printed anywhere it's needed. An important feature of here documents is that variable substitution occurs within them. Thus we will be able to nest subroutines by including other variables in our variable definitions. There's also a caveat: because variable substitution is performed in here documents, the dollar sign is a special character. If you want a literal dollar sign you have to escape it by preceding it with a backslash. With the exception of this rule, you can continue to write exactly the same kind of HTML that you would use in a plain HTML file.

A top-down approach

Now that we have a good HTML subroutine, we can analyze the whole page into logical pieces and then reassemble them. Taking a top-down approach, the page as a whole will look like this:

$html = <<< EOF
  <html>
  <head>
    <title>{$title}</title>
    {$style}
  </head>
  <body>
    {$header}
    {$mainbody}
    {$footer}
  </body>
  </html>
EOF;

As you can see, the whole structure of the page is revealed at a glance. Now completing the document is simply a matter of defining values for $title, $mainbody, $footer, and $style (in the final document, the building blocks will come first because they need to be defined before they are used; we are working backwards here to show the structure of the document).

The footer is easy:

$footer = <<< EOF
  <table width="100%" bgcolor="#d0d0d0" border="0" 
    cellspacing="0" cellpadding="0">
    <tr>
      <td><p align="center">This is the footer.  (c) 2006</td>
    </tr>
  </table>
EOF;

So is the style:

$style = <<< EOF
  <style type="text/css">
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
      border: none;
    }
    #full { height: 100%; }
  </style>
EOF;

The main body of the document, stored in the variable $mainbody, calls three other HTML subroutines:

$mainbody = <<< EOF
  <table width="100%" border="0" cellspacing="0" cellpadding="0" 
    id="full">
    <tr valign="top">
      <td nowrap bgcolor="#d0d0d0" width="125px">
        {$leftcolumn}
      </td>
      <td>
        {$content}
      </td>
      <td nowrap bgcolor="#e0e0e0" width="75px">
        {$rightcolumn}
      </td>
    </tr>
  </table>
EOF;

Once again here, the use of subroutines helps reveal the structure of the document, making it much easier to edit the table to make layout changes, for example.

The remaining code fragments are straightforward. The left column:

$leftcolumn = <<< EOF
  Menu a
  <br/><a href="item1">Item 1</a>
  <br/><a href="item2">Item 2</a>
  <br/>
  <br/>Menu b
  <br/><a href="item1b">Item 1</a>
  <br/><a href="item2b">Item 1</a>
EOF;

The content:

$content = <<< EOF
  <p>
    This is the main content.  Alice was beginning to get very
    tired.  It was a dark and stormy night.  Call me Ishmael.
EOF;

The right column:

$rightcolumn = <<< EOF
       <a href="http://example1.com/">Link 1</a>
  <br/><a href="http://example2.com/">Link 2</a>
  <br/><a href="http://example3.com/">Link 3</a>
  <br/><a href="http://example4.com/">Link 4</a>
  <br/><a href="http://example5.com/">Link 5</a>
  <br/><a href="http://example6.com/">Link 6</a>
EOF;

And the title:

$title = "Complex table layout example";

Except for one piece, that completes the document. If you use this technique, remember to define the basic building blocks at the top of the file and the higer-level subroutines which use them next, rather than using the top-down order which has been followed here for explanatory purposes.

The last remaining piece is to actually print out all the HTML that we have painstakingly assembled:

echo $html;

Wrapping the whole thing in <php> tags and putting everything in the right order, the final document looks like this:

<?php

$title = "Complex table layout example";

$header = <<< EOF
  <table bgcolor="#7777aa" width="100%" border="0" 
    cellspacing="0" cellpadding="0">
    <tr>
      <td><h1>{$title}</h1></td>
    </tr>
  </table>
EOF;


$leftcolumn = <<< EOF
       Menu a
  <br/><a href="item1">Item 1</a>
  <br/><a href="item2">Item 2</a>
  <br/>
  <br/>Menu b
  <br/><a href="item1b">Item 1</a>
  <br/><a href="item2b">Item 1</a>
EOF;


$content = <<< EOF
  <p>
    This is the main content.  Alice was beginning to get very
    tired.  It was a dark and stormy night.  Call me Ishmael.
EOF;


$rightcolumn = <<< EOF
       <a href="http://example1.com/">Link 1</a>
  <br/><a href="http://example2.com/">Link 2</a>
  <br/><a href="http://example3.com/">Link 3</a>
  <br/><a href="http://example4.com/">Link 4</a>
  <br/><a href="http://example5.com/">Link 5</a>
  <br/><a href="http://example6.com/">Link 6</a>
EOF;


$mainbody = <<< EOF
  <table width="100%" border="0" cellspacing="0"
    cellpadding="0" id="full">
    <tr valign="top">
      <td nowrap bgcolor="#d0d0d0" width="125px">
        {$leftcolumn}
      </td>
      <td>
        {$content}
      </td>
      <td nowrap bgcolor="#e0e0e0" width="75px">
        {$rightcolumn}
      </td>
    </tr>
  </table>
EOF;


$footer = <<< EOF
  <table width="100%" bgcolor="#d0d0d0" border="0" 
    cellspacing="0" cellpadding="0">
    <tr>
      <td><p align="center">This is the footer.  (c) 2006</td>
    </tr>
  </table>
EOF;


$style = <<< EOF
  <style type="text/css">
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
      border: none;
    }
    #full { height: 100%; }
  </style>
EOF;


$html = <<< EOF
  <html>
  <head>
    <title>{$title}</title>
    {$style}
  </head>
  <body>
    {$header}
    {$mainbody}
    {$footer}
  </body>
  </html>
EOF;

echo $html;

?>

You can view the PHP version here. That's certainly a whole new look for HTML, but if we take a moment to think about what has been accomplished here, we'll realize that subroutines like $mainbody and $html are high-level patterns that can be easily reused to create a great variety of documents by varying the lower-level subroutines they call.

Critiques

If you are a fan of complex PHP template systems like Smarty, my technique may seem simplistic. However, template systems like Smarty have two disadvantages: they force programmers or designers to learn an entirely new language (and you have to pick the right one, or you will be orphaned), and they limit you to the features that the designers of the template language have had time to implement. Using the technique I have been describing here, you are only limited by what PHP is able to do. And your programmers and designers continue to use their favorite languages (PHP and HTML) without any disruption. There are also performance considerations: a template engine is basically an interpreter written in PHP, and it can never be as fast as the underlying language. My system uses built-in features of PHP and should be considerably faster than a template engine.

I may be criticized for using HTML tables to lay out the document, to which I say: You can't expect me to use good CSS design techniques, I'm just a programmer. More seriously, I used table layout intentionally because it results in ugly HTML when abused; thus it's a great example of the improvements you can expect from using HTML subroutines. If this technique was used more widely, table layouts might not have such a bad reputation.

Another possible problem with this technique is that it resorts to PHP, which exacts a performance hit in comparison to static HTML, simply for organizational reasons. Thus your pages load more slowly without doing anything static HTML couldn't do already. This is a good point: as a rule of thumb, static HTML can serve twice as many pages per second as dynamic PHP. However, in many cases, you won't be popular enough for this relatively slight performance difference to matter. And when it does matter, it won't be difficult to cache these PHP-generated pages as static HTML.

A final advantage of this technique is that it's a stepping stone to more complex types of dynamic content generation in PHP. Once you begin using HTML subroutines to organize your documents, it is not much more difficult to add conditional logic which reassembles the HTML building blocks, mixing and matching in response to a variety of conditions.

In this way a technique which was introduced to help get messy HTML under control, as an alternative to HTML pretty printers like HTML Tidy, can lead naturally to a more advanced approach to document generation for the web.

Comment on this article and its topic


Copyright © 2006-2008 Stephen Jungels. Written permission is required to repost or reprint this article

Valid HTML 4.01 Transitional

Last modified: Mon Oct 26 10:31:23 CDT 2009