PHP and templating engines

Update: Seems I should have read this page first… we were thinking on the same wavelength afterall. I’ll leave the post here, since I think my (and Brian Lozier’s) argument is still valid with respect to the overheads in various templating engines…


It has always fascinated me, with large-scale PHP projects, how people seem to flock to overly complicated templating engines. I’ve worked on a couple of such projects, and it got me thinking about why we do it.

My first real contact with a site that uses templating engines was the Asperger Services Australia site. Originally, it was a static-HTML site done in FrontPage, but after looking at a number of CMS systems, we finally chose TikiWiki to run the site. TikiWiki utilises the Smarty templating engine — a behemoth weighing in at just over 1MB.

Smarty wields a lot of power, able to do numerous transformations with strings — but it’s a big package, and takes quite a while to master. It also seems to occupy a lot of memory, and requires write access to directories to store “compiled” templates.

This year, we built a web application called Teamworker. Our implementation was written in PHP using MySQL, and basically it was a ground-up re-write of an internal QUT webapp of the same name (many QUT students probably know it well). For this project, we wound up using the bTemplate engine, a far simpler engine than Smarty, it uses simple string replacement of XML-like tags. It has quite a few limitations however — for instance, one cannot have two loops of the same name — it’ll substitute one, but not the other. It isn’t difficult to pick up, but some aspects of its syntax are … awkward.

I dare say if I look hard enough, there’s probably some poor sadistic sod trying to do it with XML and XSLTs. Yes, they have their place, but they’re massive overkill. If your data is already in XML to begin with (i.e. Gentoo’s site) then sure, go for it, but otherwise it seems to be (to me anyway) a really messy way to do things.

PHP, believe it or not, actually is a templating engine. It has all the features one needs. All the code I need goes inside tags like this: <?php ?>, and outside of these, I can have just about anything I want. I can also use conditional statements inside PHP tags, to control what gets displayed outside… e.g. suppose I define the variable $logged_in, a boolean, and the string $user… a webapp might have:

... random HTML code...
<?php if ($logged_in) { ?>
Hello <?= htmlentities($user) ?>.
<a href="profile.php">Profile</a>
<a href="logout.php">Logout</a>
<?php } else { ?>
Hello guest. Please <a href="login.php">log in</a>
<?php } ?>
... more code ...

Voila… done. To whistle up this template, a script only needs to initialise $logged_in and $user, then include(”template_file.php”);, and it’ll appear as they expect.

However, this requires that your templates be structured a particular way. You’re more-or-less generating things on-the-fly, rather than constructing everything in a buffer, then sending it later. This can lead to display code getting mixed up with computation code, which isn’t terrific. So in these situations, PHP needs a little helping hand. Enter, the 8-line templating engine.

PHP since version 4 supports output buffering. These allow the programmer to control when and how, data is released to the browser. In addition, it is also possible to fetch the rendered output from the buffer as a string then clear the slate. This gives us great power to create a very simple but flexible templating engine, in 8 lines of PHP code:

function doTemplate($templateFile, $data) {
extract($data);
ob_start();
include($templateFile);
$_out = ob_get_contents();
ob_end_clean();
return $_out;
}

It’s crude, but it works. A site can then be easily put together using this method. No files need to get written at runtime, there’s no special syntax required. The idea is the template files are just very trivial PHP scripts — one uses as few functions as possible to achieve the desired page output. So built-in functions such as if, foreach and similar constructs, and maybe the odd include(). A site might use an overall template like the following:

<html>
<head>
<title><?= htmlentities($page_title) ?></title>
</head>
<body>
<h1><?= htmlentities($page_title) ?></h1>
<hr />
Navigation: <?php foreach($navlinks as $link) { ?>
<a href="<= $link["target"]; ?>”><?= htmlentities($link["title"]) ?></a>
<?php } ?>
… other header stuff …
<?= $content ?>
… rest of page

They may, for instance, have some form widgets. Suppose they wanted all these boolean values to use radio buttons with some sort of tick/cross image beside them? They can define the HTML code for them in one place…

<input type="radio" value="no" name="<?= $name ?>" id="<?= $name ?>_no" /><label for="<?= $name ?>_no"><img src="/images/cross.png" alt="No" /></label>
<input type="radio" value="yes" name="<?= $name ?>" id="<?= $name ?>_yes" /><label for="<?= $name ?>_yes"><img src="/images/tick.png" alt="Yes" /></label>

Then use that widget repeatedly in a document by simply defining some place holders (using <?= $placeholder_name >) and generating the page…

$my_page["show_email"] = doTemplate(”templates/yesno.tpl.php”,array( “name” => “show_email” ));
$my_page["subscribe_annouce"] = doTemplate(”templates/yesno.tpl.php”,array( “name” => “subscribe_announce” ));
//
// … other definitions …
//
$page_content = doTemplate(”templates/register.tpl.php”, $my_page);
echo doTemplate(”templates/overall.tpl.php”, array(
“page_title” => “Register for our forum!”,
“content” => $page_content,
“navlinks” => $navigation // <– This may be a global array that’s manipulated in various places as needed.
));

Already, that works in much the way bTemplate does, but doesn’t have nearly as many limitations. There are some manipulations that it can’t do as easily as Smarty does them, such as inline manipulations of text, but then again, it’s a heck of a lot more lightweight. Sure, RAM is cheap these days… but still, why waste the resources if you don’t have to? What I’ve done above, could be viewed as wasteful — even the very act of using PHP in the eyes of some, but sometimes we don’t get a say in that matter, we work with the tools we have at hand. (Heck, I’ve been known to use C and Busybox ash to construct webapps — which works surprisingly well too.) But even in this age of cheap computing power, I think striving for minimalism is still worthwhile.

Leave a Reply


Bad Behavior has blocked 307 access attempts in the last 7 days.