For my last project, I had to use PHP and managed to make it fun by —among other stuff— rewriting a templating tool. Templates was one of the first thing we did with Batiste for doSimple. It was qregexp based, not very flexible, ugly and for sure, inefficient.
Let’s redo this, keeping in mind that PHP is already a templating language.
<!DOCTYPE html> <html lang=<?php echo $lang ?>> <?php echo $html ?> </html>
This is valid PHP, and can be seen as a template with two parameters: the language ($lang
) and some html content ($html
).
<?php $lang = "en"; $html = "<h1>Hello World!</h1>"; // the file above include("hello.php");
That was too easy. But it’s not very clean, imho because you cannot do anything with the result. Let’s do this a little bit better.
<?php function template($template, $args) { extract($args); ob_start(); include($template); $result = ob_get_contents(); ob_end_clean(); return $result; } echo template("hello.php", array("lang" => "en", "html" => "<h1>Hello, World!</h1>"));
This way, you don’t pollute the global scope with variables and are able to reuse templates. It’s still very, very basic but will enable you to understand the final class Template that is used by bluespirit.ch. I’ll show you how it works but let you dive into the PHP code to understand it.
<?php // templates is a directory $tpl = new Template("templates"); echo $tpl->index(array("title" => "Hello", "links" => array(1,2,3));
Now the templates, let’s start with the index (the function call above is in fact using __call).
<?php $this->inherits("layout"); $this->block("head") ?> <title><?php echo $title ?></title> <?php $this->endblock(); $this->block("body") ?> <h1><?php echo $title ?></h1> <ul> <?php foreach($links as $link): ?> <li><?php echo $this->link(array("link" => $link)) ?></li> <?php endforeach ?> </ul> <?php $this->endblock();
The layout, from which this template inherits.
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <?php $this->block("head") ?> <title>Untitled Document</title> <?php $this->endblock() ?> </head> <body> <?php $this->block("body"); $this->endblock() ?> </body> </html>
and link, of course.
<?php echo $link
Which could have been more complex.
That’s the very basics, the final one includes more features like some block control meaning you can no only override a block but also append or prepend some content which is very useful for the usual end of the page scripts. Another one that I like very much is some cache (using APC (or apc_alt) enabling avoiding regenerating a piece of layout everytime.
Having this kind of cache also means that you might ending up doing bad things in the templates (views) like SQL requests. This is for example used on the homepage of bluespirit.ch where the news are coming from a RSS feed parsed by Yahoo! Pipes. It doesn’t cURL it all the time.
All this in on GitHub, get it, fork it, fix it. And I’ve got one question for the PHP masters in the room, how do you do monkeypatching in PHP? (I know how much evil it is, but I promise that I won’t break anything)