Useful template engines
Have you ever wondered why the web application scripts are written in such languages as PHP instead of C and C++? Or why we are not programming in Pascal? The popularity of “web” languages comes from satisfying the programmers’ needs and innovations, thus letting to create the websites faster and cheaper. However, in this post I will not discuss the officially recognized languages. Instead, I am going to analyze the template engines, a part of web applications concerning on producing the HTML output which has a lot in common with programming language issue.
Probably everyone of you were or have been using a template engine. Probably many of you still use it in your projects without recognizing this. The name template engine can be given to any type of library which stores the output scheme in a separate file called "template". They appear in every popular framework, such as Symfony or ZF. The only difference is that they use pure PHP language to design and write templates. It seems that a well-tested and feature-rich language is a good choice for it. We can make use of our currently possessed skills, and we simply must pack some commonly used stuff into classes and functions. However, there are no perfect solutions. Originally PHP was designed to be a "template" language, but nowadays, it is much more universal and becomes an application-oriented tool. Similarly to scripting languages that dominated the web world and Java, ruling in the business application market, template engines are another field of interest, where one could create someting innovative, better than PHP. In the next part, I will focus on the template engines only.
A custom language
Many programmers do not like "custom" templating languages. They claim their biggest drawback is that one must learn them first in order to apply in a project, whereas he or she already knows PHP. Again, I refer to the history. In 1990-s, people could also say that C and C++ are better for business applications than Java, because they knew C/C++, but not Java which must have been learned. Fortunately, they did not, because Java offered them a new approach to the commonly encountered problems, making them simpler to solve and reducing the complexity. The following fact should be obvious for everyone: when creating a new programming language, we can do almost everything, including the reduction of complex and annoying operations to simple instructions or even hiding them from a programmer. For example, PHP represents a class of imperative languages which means that the programmer teaches the computer step-by-step, how to solve a particular problem, using loops, conditional instructions and functions, but it is not the only "correct". A very important language groups, especially in science, is formed by functional languages, such as Haskell, Lisp or Erlang. By the way, the popular XLST is functional, too. There are much more programming paradigms. Personally, one of my favourite ones is declarative programming. We do not describe there how to get to the result, but rather how it should look like. An example of declarative language is SQL wher we define a set of conditions and constraints on the data must match in order to satisfy our needs. Please note, in this particular case we can also ask: why we cannot use a special API or language to manipulate the database directly, instead of learning yet another language? Of course, because in a higher period of time, it is more effective to say: find me every people with last names beginning with A instead of writing the searching algorithm from scratch, even with the most powerful API one could imagine.
A typical templating language
A typical templating language is imperative, just like PHP. We have some loops and conditions there and we can use them to code the presentation logic. Although PHP does not exhaust the topic of imperative languages (please take a look at Icon language to see what else can be improved and how), the general philosophy remains the same. The sad thing is that many template engine authors do not try to design an innovative language. Their projects offer fewer features than PHP, making many problems harder to solve, and to make things worse, they reproduce its limitations. For example, there are only a couple of languages that provide something similar to PHP functions. When it comes to the rest (including popular Smarty), we lack the possibility of save a piece of code in one place and reuse it across the project. At the same time, in PHP we can pack it into functions or classes, of course without mentioning the elegance and simplicity of such step.
Small templating languages cause even more problems. Their authors either do not have enough skills to implement the basic functionality or claim that "they need just a simple template engine". As a result, they are beaten by simple problems. To be honest and clear - a language which does not provide even the basic loop or conditions is too limited to run a typical website.
Let's take a look at Smarty. The most common problems encountered in templates are list/variable displaying, conditional show of a code and form processing. Does this library brings anything that could be considered as innovative? Despite the new syntax - absolutely no. We still use the same foreach, display variables much like in PHP, and process them like in PHP. Form rendering code is also rewritable line-by-line to the corresponding PHP source. Every problem we can imagine must be programmed manually by the template designer, producing a write-only code, hard to maintain and understand. The helpers do not help us very much, because we either close the way to customize the form look or we still have too much coding:
<div class="odd<?php echo (!empty($errors['name']) ? ' error' : ''); ?>">
<?php if(!empty($errors['name'])){ ?>
<p class="error"><?php echo $errors['name']; ?></p>
<?php } ?>
<label for="form_name">Name</label>
<?php echo form::input(array('name' => 'name', 'id'=>'form_name', 'value' => $form['name'], 'class'=>'inputText')); ?>
</div>
Smarty:
<div class="odd{if $errors} error{/if}">
{if $errors}
<p class="error">{$errors}</p>
{/if}
<label for="form_name">Nazwa</label>
{input name='name' value=$form[value] class='inputText'}
</div>
The presented snippets come from a real project. In case of one or two fields it is not a problem, but there we had a couple of forms with approximately 5-6 fields in each, and there are much bigger projects in production. The most annoying problem is code redundancy. If we must change one CSS class or improve the HTML code structure, we must visit every form and every field in the project in order to change it. If we pack everything into classes or functions, but this will make the customization very tricky, especially if the code structure is very complex. Such situation occurs in Zend Framework, where the change of one HTML tag requires the programmer to reimplement classes and invent a way to apply them in order not to break the MVC pattern (a design failure in ZF). At the same time, Symfony introduces template templates which lack the documentation. In both cases, applying a specific design to just one field with leaving the default one for the others or providing a non-standard form layout is very problematic and requires lots of work.
Although in PHP it is a bit impossible to make it simple and natural due to the language limitations, we can design a new language, capable to find the form fields and apply a common design with keeping the functional parts, such as label generation or error reporting. During the compilation, the compiler produces a code similar to above, but from the template designer's point of view, everything looks fine. If he wants to change the layout, he fixes it in one place in the template and the change is automatically propagated to the rest of the fields.
For PHP, everything that does not look like PHP is a static text. However, while desiging a web application, we work with HTML or XHTML which is completely not understood by PHP. It means that it is not very helpful for generating valid output documents. We encounter similar problem in other template engines that treat the document as a static text with their own tags. In the past, I used to see it as a feature, but later I changed my mind. The non-XML documents are very rare in the web, and at the same time it was more and more annoying to look for the layout problem, wondering why this stupid menu does not look as it was supposed to. It was even worse when the improperly closed tags were found in the finished application...
Expectations
With declarative approach and providing the features impossible to get in pure PHP, a skilled and creative programmer is able to design a language that is really helpful for writing templates. I agree that it must be learned, but it should be treated as long-term enterprise used in many different project for years. For me, the situation is clear. I prefer to spend my time on learning the technology well and solve the problems in 5 minutes instead of 30. Moreover, many people forget that view helpers provided by frameworks must also be learned and they can be quite complex, too.
Let's see where the new template language could help us:
- Data filtering - in PHP and most of the template languages, the programmer must publicly call a function like
htmlspecialchars(), because the language will not help him. This makes the template design process more time-consuming and the code harder to edit and maintain. - List rendering - in templates, we usually display simple lists or nested lists connected with a relationship, i.e. categories and their products. In PHP and Smarty we connect them manually and a brief look at the discussion boards shows that it could be a serious problem. We must also take into account used data structures, iterators, differences between arrays and objects etc.
- Form processing - almost every website uses forms. I am very surprised that so far, nobody have invented a way to improve the form rendering at the template engine level, and by improving I do not mean providing three or four helpers that must be still configured manually.
- Template modularization - the output code is a concatenation of smaller templates, so that we do not have to duplicate the header and footer in all the files.
- Extensions for specific needs, i.e. displaying the data in columns. Maybe it is not a very hard problem (we just have to check the modulo division result), but the code is quite ugly and harder to maintain. Despite my own OPT 2, I have known only one template engine so far that offers a way to deal with it: TinyButStrong.
- Understanding HTML and XML. Informing about improperly closed tags is just the beginning. Have you ever tried to add an attribute/list of attributes conditionally, or make their values dynamic in PHP or Smarty? It leads to the code write, forget how it works and do not try to get back to it. Life would be simpler if the template engine knew, how to add attributes to XML tags.
Of course, the list could be much longer, depending on who is going to write it. For example, I consider foreach as too limited when it comes to support the different data formats. Some of the logic can be hidden in iterators, but more complex cases simply require to write some extra code at the template level. However, the new language can have better capabilities to hide it.
Performance
It is very common to hear that template engines are slow. It is true, but only in case of libraries that attempt to execute the template from A to Z. In fact, almost all template engines compile the template to the PHP code and the compiler is loaded only when necessary. During normal operation, the library loads only a small programming interface to communicate with the application and launch the template execution whose performance is basically the same. I know API loading costs a bit, but please do not be silly... do the programmers claim that the cost of loading Zend_View or Zend_Layout is equal zero? Sorry for the language, but it is a total bullshit. If we want to separate the logic from the presentation, we have to load some extra code, no matter whether we write our templates in PHP or in something else. The fact that the API of most template engines is a bit messy is a different story.
The compilation has some important advantages over manually written PHP code:
- The compiler does not have to deal with the code elegance. The produced code does not need to be clean and readable, so it can use simpler but faster language constructs.
- Some of the problems can be solved during the compilation, whereas PHP must deal with them during execution (i.e. form layouts).
- The programmer does not have to have a time to optimize the templates or does not know such optimizations. At the same time, if the compiler author discovers a performance problem, he can make a fix and the changes will be applied to all the project without the need to change a single line of template code.
We must remember that the more complex template is, the harder task is to manage the applied optimizations, keeping the code clean at the same time. It is not an accident that C programs are often faster than those ones written in assembler - currently only the most talented and intelligent programmers can beat the compiler in the optimizer role.
What not to use?
Do you look for something better than PHP? The following template engines will not help you much:
- Smarty 2 - does not need to be introduced. The development stopped years ago, but surprisingly it did not resulted in popularity loss.
- Smarty 3 - the recent improvement of Smarty. Although the code is finally PHP5-compliant, the basic philosophy is still the same and the changes are not revolutionary.
- Dwoo - de facto a reimplementation of Smarty, with all its drawbacks.
- Open Power Template 1.x - although it offers some declarative aspects, the template engine does not satisfy most of the mentioned needs.
- All the Smarty-like template engines.
What to use?
Every time I write about template engines, I must deal with a small ethical problem, as I am an author of one of them. It is rather obvious that I am not a masochist and it is going to meet my practical observations and private opinions. This is why I will start a bit differently. There are only few interesting libraries, so they are worth mentioning in the first place:
- TAL (Template Attribute Language) - the language for the Python project Zope. In PHP it is available thanks to the PHP-TAL project. TAL is an XML application adding extra attributes to manipulate the content and the TALES expression language.
- XSLT - XSL transformations are very powerful and mature tool for processing XML documents. Unfortunately, the use in PHP is a bit problematic, as the script must generate the XML file with the data in the first place, and then process it with XSLT.
- patTemplate - a template engine with fully declarative approach. It does not even contain a conditional instruction. I have not tested it in practice due to the incomplete documentation and lack of time, but it looks interesting.
- TinyButStrong - I mention this library as a curiosity, because it offers some nice, declarative constructs. Unfortunately, the library is extremely slow, because the templates are not compiled to PHP.
Open Power Template 2 is described in the last place, separately. The 2.0 version aims to support all the mentioned features + some more. When I found a common templating problem, I started looking for an elegant solution free from PHP language limitations and implemented it in OPT, so I am rather sure that it satisfies my needs. However, looking at the huge amount of work required to write it and the fact that my needs are higher and higher every year, at least some of you should also find it useful. Even now I see many issues that could be improved and a big number of functionality was implemented thanks to user requests, including the existence of 2.0 version itself. This is the end about Open Power Template in this post.
Why are there so few innovative projects?
The reason is simple: time and complexity. Even the implementation to the place where the template engine does not limit us contrary to PHP, is a quite demanding task. The extra functionality means the next hours spent on desing and implementation and before we start it, we must also think that it could be useful. Without the smaller template engines written between 2002 and 2004 and OPT 1.x developed between 2004 and 2008, probably I would not be able to write even a half of the functionality of OPT 2. Moreover, development of the last version took me 1.5 years because of the complexity and the need to operate on a completely new abstraction level. We cannot count on framework designers. They have the entire environment to write and no time to focus for so long on just one element. I think these are the main reasons why the template engines usually provide a small subset on PHP, and indirectly cause problems with accepting the idea by many programmers.
Summary
The idea of this note is not to convert anyone to become a template engine fanatic. There can be heard many myths about template engines and I rather wanted to explain the real nature of them and show some nontrivial aspects of having a new template language. It is not hard to encounter posts and opinions where the authors who actually use a template engine (i.e. Zend_View) produce texts entitled 'Why template engines are evil' or try to compare them to frameworks which is a nonsense. PHP is not the best language that will solve all your problems, and if there is something that could be improved, it means that there can exist something better and sooner or later, someone will write it.