Thoughts on Smarty.
March 9, 2003
A couple months ago I started using Smarty, a templating system for PHP. It's something that I'd meant to do for a long time but kept getting distracted by other things, namely an overwhelming workload. Finally, an opportunity to work with a student intern gave me the excuse I needed to make the time. It's been an interesting ride.
Smarty is billed as a way to separate application logic from presentation. This makes design, development, and debugging much easier.
Here's a sample PHP file using Smarty (necessarily abbreviated):
<?php
require_once('Smarty.class.php');
$smarty = new Smarty;
/*
* insert code to connect to database and build
* the $people array, where:
* $people[0]['name']='Bill Moyers';
* $people[1]['name']='Bob Edwards';
*/
$smarty->assign('people',$people);
$smarty->display('index.tpl');
?>
that uses this template (index.tpl):
<html><body>
<ul>
{section name=id from=$people}
<li>{$people[id].name}</li>
{/section}
</ul>
</body></html>
to produce this output:
Once you get past such a trivial example, this is much, much nicer to work with than mixing PHP code with HTML.
My first thought when I started working with Smarty was, "oh great, it's got its own little mini-language, completely different from PHP itself. How terribly unhelpful." And I still think that. There is a strong temptation in templating systems to introduce all sorts of complexity, including control structures that bear more than a passing resemblance to those that you're probably trying to avoid by using templates in the first place. How different is the above section
loop different from a PHP equivalent?
<html><body>
<ul>
<?php
foreach ($people as $name) {
echo "<li>$name</li>";
}
?>
</ul>
</body></html>
Not terribly. But I'm not sure that matters.
Before you fall for the hype that is often associated with templates — that programmers can focus on programming while designers can focus on design and not have to deal with nasty things like variables and logic — let me tell you now that Smarty does nothing of the sort for you, as is made clear from the get-go in the documentation: "Smarty does not attempt to completely separate logic from the templates. There is no problem with logic in your templates under the condition that this logic is strictly for presentation."
This distinction between application and presentation logic is not so tenuous as it might seem at first. Application logic involves things like handling sessions and database connections, applying or interpreting business processes, or determining which page views to display. It makes sense to keep that separate from your HTML, with both design and maintenance benefits. Displaying a data set as multiple table rows, paragraphs, or a bulleted list… these issues of presentation involve a certain logic and so the code for that can and may need to be more closely connected to the HTML. Maybe it's not ideal, but it works. For years I've been trying out different ways of handling this distinction but hadn't put it in those terms. Smarty helped me clarify the idea and my coding has improved as a result.
Smarty has some serious annoyances, like the bizarre differences between the syntax of two looping functions, foreach
and section
. Both these loop over an array $custid
(the difference being that foreach
is used for associative arrays):
{section name=customer loop=$custid}
id: {$custid[customer]}
{/section}
{foreach item=curr_id from=$custid}
id: {$curr_id}
{/foreach}
There may be good reasons why foreach
uses from
to mean essentially the same thing as section
's loop
. Or maybe it's a historical accident. I don't care: I can never keep them straight. There are worse examples, that's just the one that bugs me the most.
There are some terribly cool things about Smarty, though, that will keep me using it. When a PHP script that uses a Smarty template is first run, Smarty compiles the templates into PHP code, so the template doesn't need to be parsed on every invocation. This is a nice little performance boost. What's more, Smarty can cache a static HTML page, so if your data doesn't change all that often you don't need to connect to a database for every page view: just send the static page. Control over page caching can be very fine-grained.
Another way Smarty helped me improve my code is in forcing me to simplify. When pressed for time (as in, "Oh by the way, here's a little something that needs to be done in half an hour"), I've been known to use multidimensional arrays with wild abandon. Something like this is pretty representative:
$presentation[2]['presenter'][3]['fname'] = 'John';
This is potentially confusing for someone who has to debug the code later, especially if the code that loops over that array is all mixed up with the HTML. And even though I'm knocking the code out in a hurry for a one-time thing, it will come back to haunt me. Guaranteed.
Limitations in Smarty's syntax help me avoid situations like this. It may be possible to loop over the array with Smarty functions, but it's a pain in the ass. So I simplify and take the time to break it into multiple arrays or objects. In the end, the code is often more efficient and is definitely easier to maintain.
Rule of thumb: if I find myself struggling with how to manipulate a data structure, it's too complex.
Something else occurred to me after I started using Smarty: I don't have to use PHP anymore. Perl has all sorts of template systems, such as Template Toolkit, HTML::Mason, HTML::Template, or even Text::Template (a kick-ass module that has saved me boatloads of time). These rarely seem like a good fit, though, and if I'm going to do the sort of larger project that makes Mason really shine, I'm more likely to use AxKit. I'll likely stick with Smarty for smaller projects on which I need some very fast turnaround.
One final note: I just discovered Phrame, an MVC platform based on Struts. In PHP. Combined with Smarty, this could make for some interesting work. More later, once I've had a chance to play with it.