Probably all of us have used template engines in one form or another. Some might even like template engines for whatever reason, but let’s think about it for a moment: are they actually making our lives easier?
Most template engines simply wrap PHP (or some other language’s) syntax into their own syntax, and maybe they look a little bit cleaner when mixed with HTML. Some may even provide useful features like automatic variable escaping to prevent XSS vulnerabilities.
But does this actually significantly reduce the amount of code needed to write some common scenarios, or make it easier to read/manage the code?
Case 1: tables
Tables are an excellent example of what I mean. Sometimes you may want to display a table’s first row with a different style than others, or maybe you want to display every second row with a different style?
The typical way to achieve this is to create a variable in your template and compare against it in the loop:
<?php $first = true; ?> <table> <?php foreach($rows as $row): ?> <?php if($first): ?> <tr class="firstrow"> <?php $first = false; ?> <?php else: ?> <tr> <?php endif; ?> <td><?php echo $row[0]; ?></td> <td><?php echo $row[1]; ?></td> </tr> <?php endforeach; ?> </table> |
So there’s some extra cruft, but it’s not so bad. Consider the following in Smarty, which does about the same:
<table> {foreach from=$rows item=row name=loop} {if $smarty.foreach.loop.index == 0} <tr class="firstrow"> {else} <tr> {/if} <td>{$i[0]}</td> <td>{$i[0]}</td> </tr> {/foreach} </table> |
Pretty much the same. Only big difference is that you didn’t need to declare the variable yourself.
Couldn’t this be done with some less code? Or maybe with some more HTML-like and simpler to read code? Here’s how it could look:
<table tpl:var="rows"> <tr class="firstrow" tpl:type="first"> <td>1st</td> <td>2nd</td> </tr> <tr> <td>3rd</td> <td>4th</td> </tr> </table> |
Here, the template engine could loop through rows, and display the tr with the type attribute only as the first row, and use the other tr for the rest of the rows. It would also automatically fill the td’s using the indexes from the array.
I think the last snippet is better than the PHP and Smarty versions. You may notice some similarities to PHPTAL, but the example is much less verbose than PHPTAL’s templates. It could even be condensed some more: we could omit the td elements inside the first tr – the engine could just guess that you want to use the same tds as in normal rows, which is a reasonable assumption. You could, of course, always provide the html inside the first tr as shown in the example.
Using this kind of template markup, you need to write less code to achieve the same result. Not only that, but the markup is cleaner because you don’t have PHP mixed in with HTML, so the code becomes easier to read and modify in the future.
Case 2: filtering
This is another common scenario: You’ll want to filter your variables so that users can’t insert arbitary HTML snippets or other malicious code.
Typical PHP code for it would be something like this:
<div> <h1><?php echo htmlentities($title); ?></h1> <p><?php echo htmlentities($content); ?></p> </div> |
And typical Smarty example:
<div> <h1>{$title|escape}</h1> <p>{$content|escape}</p> </div> |
You could say the Smarty example is a bit better as it requires less typing, but you’re still repeating the escaping.
How about this:
<div tpl:filter="htmlentities"> <h1 tpl:var="title">example title</h1> <p tpl:var="content">example content</p> </div> |
We declare a filter attribute on the div, and then use a var attribute for the child elements. The var attribute would replace the example content in the nodes, and it would “inherit” the filter behavior from the parent div element and use htmlentities to escape the variables. No repeating for filter, and if you add some new tpl:var calls inside the div, you won’t need to remember to add the filtering code to it like you would have to if you were using pure PHP or Smarty.
The engine could also support automatic filtering. In that case, you could disable filtering, or change to a different filter function, by using the filter attribute.
More on different attributes
Of course, just having these few features wouldn’t make the engine really useful. You could extend the idea to providing an easier way to write forms, or outputting values from a class instance.
For example, when writing a form, you often have to output error messages or other such things. A good template engine should allow you to define this without having to resort to using lots of if-elses or other tricks.
Outputting values from class instances could also be made a bit simpler. For example, you often have a specific element inside of which you output specific values from an object. For example, a user details box on their profile. We could have the engine do something like this:
<div tpl:var="user"> <h1 tpl:method="getName">User's name</h1> <p>Registered: <span tpl:method="getRegistrationDate">YYYY-MM-DD</span></p> </div> |
The above could even be expanded a bit further: In the span element for the registration date, we could have the template engine read the date format from the span, so that it gets formatted into the format inside the element.
You could also use tpl:method for calling any object’s methods, if the object was provided to the template. For example, tpl:method=”myObject.someFunction” could call $myObject->someFunction() in context of the template.
It should also allow you to write PHP in the templates if you wanted. You can’t expect that the template language is enough for everyone, and there is no real reason to not allow PHP in the templates as the idea is to make it easier for the programmer.
Conclusion
If a template engine did let met deal with typical cases like these using less code and by making it simpler to understand the code, I think I would use it.
In addition to that, it should let me use PHP in the templates if I wanted. Sometimes you just need to use PHP for more flexibility. It should also be easy to extend, so that you can write custom attributes or maybe even tags.
I’ve actually implemented a basic template engine, which supports var and filter attributes. There are, however, some challenges in implementing the features so, that writing custom components for it does not get too complex. There’s also the issue of the template compiler: you can’t really parse all of those on each page request, so the custom components would require an easy way to tell the compiler what it has to do to be able to compile them.
I think a template engine should perform more tasks for you and not expect them from you. Similar to having a higher-level programming language, the template engine should be a higher-level language for writing templates more efficiently and so that the result is easier to manage.
It should be about making the programmer more effective – not about safeguarding him from writing PHP inside the templates because it’s “bad”.
Please share your thoughts on the examples. Also, how would you improve writing templates?
Further reading:
On template “Tag Soup”
Different PHP template engines