25 Jan 2019 - by 'Maurits van der Schee'

Instead of choosing Twig, Mustache or Smarty as PHP templating language I decided it would be much more fun to write my own. In 165 lines I wrote a sandboxed templating system that supports 'if' and 'for' and can be extended with functions.

Considerations

The code does not use regular expressions, but it tokenizes and uses a syntax tree (without any dependencies). This means that it supports nested 'for' and 'if' constructs. The syntax looks a bit like Mustache and Twig, but is stricter to optimize for rendering speed. It outputs rendering errors in the rendered output, so that you can easily debug it as a user.

Basic syntax

For my (limited) purpose I only needed the following API:

render($template,$data,$functions);

Which allows something like this:

render('hi {{name|cap}}', ['name'=>'maurits'], ['cap'=>'ucfirst']);

The output is:

hi Maurits

Note that you can chain multiple functions using the '|' character.

Errors

And errors are shown in the output:

render('hi {{name|cap}}', ['name'=>'maurits'], []);

Outputs:

hi {{name|cap!!function 'cap' not found}}

The double exclamation mark is used to indicate the start of the error message.

For loops

For (each) loops are also supported:

render('test{{for:i:numbers}} {{i}}{{endfor}}',['numbers'=>[1,2,3]]);

This outputs:

test 1 2 3

Note that the variable you define is added to the data array during the loop.

If statement

Conditional (if) blocks are also supported:

$eq = function($a,$b){return $a==$b;}; render('{{if:n.m|eq(3)}}m is 3{{endif}}',['n'=>['m'=>3]],['eq'=>$eq]);

For the above code the output is:

m is 3

As you see the functions can be anonymous and nested data is supported. Note that the first argument of a function is automatically filled with the expression that is precedes the '|' (pipe) character. This is why the 'eq' function is defined to have two arguments ('a' and 'b') but only takes one in the syntax.

Performance

PHP is a fast and complete templating language and you should use it where you can. Unfortunately it does not support secure user-defined templates. This code does support sandboxed templating and it is easy to understand. Even if you don't use the code (it is MIT licensed), the code may be educational to read. You can find the code here:

https://github.com/mintyphp/core/blob/master/src/Template.php

PS: Liked this article? Please share it on Facebook, Twitter or LinkedIn.