Overview
Around the end of 2009, I wrote a simple templating system for PHP/HTML to be used in-house by our designers for brochure-ware type websites. The goal of the system is to allow templating in otherwise pure HTML via custom tags that are processed by PHP. For example, a templated page might look like this:
<tt:Page template="templates/main.html">
<tt:Content name="leftColumn">
<p> blah blah </p>
...
</tt:Content>
<tt:Content name="rightColumn">
<p> blah blah </p>
...
</tt:Content>
</tt:Page>
The template itself might look something like this:
<html>
<head>...</head>
<body>
<div style="float:left; width:45%">
<tt:Container name="leftColumn" />
</div>
<div style="width:45%">
<tt:Container name="rightColumn" />
</div>
</body>
</html>
Besides the Page and Content/Container tags, there are a few other tags included in the core for stuff like flow control, iterating over a collection, outputting dynamic values, etc. The framework is designed so it's very easy to add your own set of tags registered under another prefix and namespace.
Custom Tags to PHP
How do we parse these custom tags? Since the're no guarantee that the HTML file is well-formed XML, solutions like XSLT/XPATH won't be reliable. Instead, we use a regex to look for tags with registered prefixes, and replace those with PHP code. The PHP code is a stack-based design... upon encountering an opening tag, an object representing the tag is created pushed onto the stack, and its "initialization function" (if any) runs. Whenever a registered closing tag is encountered, the most recent object is popped off the stack, and its "rendering function" runs.
So, after the framework replaces the templating tags with PHP, our example page might look something like this (in realty it's a bit uglier):
<?php $tags->push('tt', 'Page', array('template'=>'templates/main.html')); ?>
<?php $tags->push('tt', 'Content', array('name'=>'leftColumn')); ?>
<p> blah blah </p>
...
<?php $tags->pop(); ?>
<?php $tags->push('tt', 'Content', array('name'=>'rightColumn')); ?>
<p> blah blah </p>
...
<?php $tags->pop(); ?>
<?php $tags->pop(); ?>
The good, the bad, and eval
Now, how to execute our newly-generated PHP code? I can think of a few options here. The easiest is to simply eval
the string, and that works well enough. However, any programmer will tell you "eval is evil, don't use it..." so the question is, is there anything more appropriate than eval
that we can use here?
I've considered using a temporary or cached file, using php://
output streams, etc, but as far as I can see these don't offer any real advantage over eval
. Caching could speed things up, but in practice all the sites we have on this thing are already blazingly fast, so I see no need to make speed optimizations at this point.
Questions
For each of the things on this list: is it a good idea? Can you think of a better alternative?
- the whole idea in general (custom tags for html / php)
- converting tags to php code instead of processing directly
- the stack-based approach
- the use of
eval
(or similar)
Thanks for reading and TIA for any advice. :)