on Sep 20th, 2008PHP Templating in 5.3+
So, if you read my last post about pQuery you’d be familiar with me working on a way to enhance the PHP templating “experience”. I wasn’t very happy with how pQuery-0.1 turned out in the end as it’s way to bulky to split it up in several files, so I started glancing at PHP5.3 and what I could (ab-)use closures for. The technique I came up with borrows the DOM-hierarchy from pQuery but allows you to embed the layout code inside the templates, without mixing it with HTML.
How is this achieved? Well through a combination of some of PHPs lesser known features, namely:
- The ability to return things from included files with the syntax
$result = include 'file.php';if you have a return statement in your include file. - If you have php-tags in the top of an XML-file it’s interpreted by the xml parser as a part of the xml document in the same way that is, but is ignored.
- Closures in PHP5.3
So, let me give you a “small” template example, and let me explain how it works.
<?php
return function($tree, $data) {
$tree->root->body->ul[1]->li->loop($data, function($tag, $item) {
$tag->h2->text = $item['title'];
$tag->p->text = $item['body'];
$tag->span->em->text = sprintf($tag->span->em->text, $item['date']);
$tag->span->em->a['href'] = "mailto:".$item['author']['email'];
$tag->span->em->a->text = $item['author']['name'];
// If empty, remove ul-list + h3 tag comment header
if(empty($item['comments'])) {
$tag->ul->remove();
$tag->h3->remove();
} else {
$tag->ul->li->loop($item['comments'], function($tag, $item) {
$tag->h4->text = $item['title'];
$tag->p->text = $item['body'];
$tag->span->em->text = str_replace(array_keys($item), array_values($item), $tag->span->em->text);
});
}
});
}
?>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>example</title>
</head>
<body id="example" onload="">
<include file="menu.html" />
<ul id="post-list">
<li>
<h2></h2>
<span class="small-text block">
<em>
Posted %s by
<a href=""> </a>
</em>
</span>
<p></p>
<h3>Comments</h3>
<ul>
<li>
<h4></h4>
<span class="small-text block"><em class="test">Posted date by name</em></span>
<p></p>
</li>
</ul>
</li>
</ul>
</body>
</html>
The closure at the top gets fed (as the first argument) the DOM hierarchy of the HTML template below the PHP tags and is then free to modify it however it sees fit, please note that the bulky assignment syntax used with both str_replace() and sprintf() is just there until I have time to put in a better already working version of it.
The jQuery-style syntax works pretty much the same way, allowing it to be extended with custom plugins (the loop()-method call you see in the php-section is a default plugin I wrote).
This approach allows you to both keep the layout and layout-code together in one file, but still separating them so you don’t have to deal with that spaghetti-mess that PHP is so well known for.
If you want to check out the code and play around with it, here’s the .zip-file just zip it up somewhere and check out example.php + example.html in your favorite editor, and of course the rest of the source if you want to, but remember - this requires php5.3-alpha.