Tags: , , , ,

Ladies and Gentleman! Welcome to the PHP Templating Celebrity Deathmatch!

I actually do like the idea behind templating. I know there are varying arguments about whether or not templating is appropriate for PHP, though those are not the focus of this entry.

The big idea behind templating is separation of concerns, that is, breaking a program into parts that are easily manageable and don’t overlap in functionality. In an ideal world, templating would provide the added advantage of allowing a programmer to be a programmer and not a web designer - and allowing a web designer to be a web designer and not a programmer - by keeping the logic underlying the presentation layer to a minimum. However, I have never found this to be true in any project I’ve worked on in my professional career.

One of the big benefits, as far as I see, is that it makes code much easier to read. This may not be true for everyone, but I would much rather be confronted with smooth, separated templated code rather than a jumbled PHP mess. It’s easier to read and far, far easier to adapt and change.

While I was attending OSCON a few weeks ago, I heard mention of a new PHP templating engine that was written in C and native compiled into a PHP extension. This would make it much, much faster than anything written in PHP itself - in theory. This project, called Blitz, was making some pretty grand claims on their website, so I wanted to put them to the test - at least a small timing test.

In this test, I am going to be comparing Smarty (the most widely used PHP templating engine and an official PHP project), Blitz (a new templating engine currently under very active development that is native compiled as a PHP extension), and standard PHP includes.

For the purposes of this test, I wrote a quick timing function that uses microtime() to record how much time has elapsed between each call of mark_time(). The code is available in the accompanying project.

A Note About The Tests

These are not meant to be exhastive tests by any means. These tests are just designed to give you 5,000 foot overview of the current state of PHP templating. They only evaluate page generation time and not other metrics such as CPU load, IO load, or memory usage. Furthermore, I selected three scenarios that I have commonly used in templating; there may be some scenarios that I haven’t tested where one method may outperform others. And, as with any benchmarking, they are dependent on my system - YMMV.

Test 1: Instantiation

This is a simple test that determines how much time it takes to power up the templating engine and get it loaded into memory for PHP to use. For the purposes of this test, we will just be comparing Smarty and Blitz, as there is no need for instantiation with a standard PHP include. We’ll start with Smarty first.

smarty_instantiation.php

echo mark_time()."<br>";
include "Smarty.class.php";
$smarty = new Smarty;
echo mark_time()."<br>";

Smarty’s instantiation time was 0.0058109760284424 or 0.005 seconds in human terms.

blitz_instantiation.php:

echo mark_time()."<br>";
$blitz = new Blitz;
echo mark_time()."<br>";

Blitz’s instantiation time was 3.0994415283203E-5, or 0.00003 seconds in human terms.

It may not seem like a big difference, but this is one area where having Blitz as a PHP extension makes a huge difference over Smarty being written in PHP and included. Because PHP must traverse the include_path to find Smarty.class before including it, it causes PHP to be slowed down before it can even instantate the Smarty object. To be fair, I decided to run a second test again with the include out of the timing mark.

smarty_instantiation2.php

echo mark_time()."<br>";
$smarty = new Smarty;
echo mark_time()."<br>";

Even without having to search the include_path for Smarty, it still took 6.5088272094727E-5, or 0.00007 seconds to instantate the Smarty object - almost twice as long as it took to instantate the Blitz object. However, this is not a realistic scenario in any way - there is no way that PHP can have saved any time and still have access to the Smarty object!

Winner: Blitz

Test 2: Simple Template Rendering

In this test, we will be comparing simple template rendering in Blitz, Smarty and PHP includes. In this test we will create a simple HTML template with two variables that need to be replaced, then render and display them to the user using each engine or, in the case of PHP, straight PHP. So, let’s get started! We’ll run Blitz first, since it won the previous test.

blitz_simple_render.php

echo mark_time()."<br>";
$blitz = new Blitz(’blitz_simple_render.tpl’);
echo $blitz->parse(array(
‘title’ => "Blitz Test!",
‘body’ => "Blah foo! I’m a body!"
));
echo mark_time()."<br>";

Blitz took an impressive 0.00011801719665527, or 0.0001 to render a simple HTML document with two replaces. Smarty’s next:

smarty_simple_render.php

echo mark_time()."<br>";
include "Smarty.class.php";
$smarty = new Smarty;
$smarty->assign(’title’,"Smarty Test!");
$smarty->assign(’body’,"Blah foo! I’m a body!");
$smarty->display(’smarty_simple_render.tpl’);
echo mark_time()."<br>";

Because Smarty is a compiling engine (it compiles the templates to PHP and caches them), the first run is always the most costly - in this case, an atrocious 0.058284997940063 or 0.06. Even on subsequent runs, 0.0065691471099854 or 0.007, again much slower than Blitz. Finally, standard PHP includes:

php_simple_render.php

echo mark_time()."<br>";
$title="PHP Test!";
$body="Blah foo! I’m a body!";
include "php_simple_render.tpl.php";
echo mark_time()."<br>";

Surprisingly, standard PHP includes took 0.00030016899108887, or 0.0003 seconds - much faster than Smarty, but three times as slow as Blitz. Once again, this likely has to do with PHP having to traverse the include_path before finding the appropriate file. If you specify the absolute path on the filesystem to the file above, the time took becomes 0.00010490417480469, or 0.0001, roughly equal to Blitz on any given run. However, because Blitz is able to parse the template with a minimum of fuss whereas I have to explicitly specify the filesystem path for PHP to get equal performance, this round also goes to Blitz.

Winner: Blitz

Test 3: Complex Templating

In this case, we are going to be doing complex templating. This test includes three template-based includes, one foreach loop over an array, and a large array of generated data. Just for the curious, the generation of the data is not going to be counted towards the timing. In this case, we have generated a 10,000 item array and are going to have each engine iterate over it.

blitz_complex_render.php

echo mark_time()."<br>";
$blitz = new Blitz(’blitz_complex_render.tpl’);
foreach($arr as $array) {
$blitz->block(’master_loop’,array(
‘id’ => $array['id'],
‘id1′ => $array['id+1']
));
}
echo $blitz->parse(array(
‘title’ => "Blitz Complex Render text"
));
echo mark_time()."<br>";

Blitz ran the test in 0.072134971618652, or 0.07 seconds, not too shabby considering it had to iterate over a 10,000 item multidimensional array.

smarty_complex_render.php

echo mark_time()."<br>";
include "Smarty.class.php";
$smarty=new Smarty();
$smarty->assign(’title’,"Smarty Complex Render test");
$smarty->assign(’arr’,$arr);
$smarty->display(’smarty_complex_render.tpl’);
echo mark_time()."<br>";

Again, because Smarty is a compiling engine, the first run is always the most expensive - in this case, a whopping 0.31642484664917, or 0.3 seconds. Subsequent runs fell in the range of 0.099456838607788, or 0.1 seconds, three times as fast as the first run but still slower than Blitz. Finally, standard PHP includes:

php_complex_render.php

echo mark_time()."<br>";
include "php_complex_render.tpl.php";
echo mark_time()."<br>";

In this test, raw PHP includes came in at 0.055343866348267, or 0.06, the fastest of all and yet just a small bit faster than Blitz.

Winner: PHP

Conclusion

Blitz won two of the three tests and came in a close second in the last. Of course, one could argue that PHP "won" the first test since there was no need to be tested on instantiation.

 Considering the short amount of time Blitz has been under active development, its sheer speed is rather amazing. From a templating standpoint, Blitz is the fastest unless you are willing to jump through lots of little hoops to make standard PHP includes work for you, and even at that point, the performance as far as total page generation time goes is roughly equal, though native PHP may have a slight advantage.

However, unfortunately, the very strength of Blitz (it being written in C and compiled into a PHP extension) is its greatest weakness. Because so many websites are served off shared hosts without the ability of users to use external extensions, most of the community will never have the ability to take advantage of Blitz. Only those with access to the machine, or more specifically the php.ini file, will have the ability to use Blitz unless it were to be merged into the PHP tree. Even in the best case, considering how many shared hosts are still running PHP4, I wouldn’t expect to see anything like this soon, if ever.

Perversely, the very weakness of Smarty (that it is written in PHP and included) is its strength, for the reasons above. Smarty is the slowest templating engine tested, however because it is just PHP, it can be included and run like any other PHP script - meaning all the people on shared hosting can make use of it with a minimum of fuss. And in Smarty’s defense, there are many features (such as template variable modifiers) Smarty has that are simply not available in Blitz. These features come with the tradeoff of a massive loss in speed. It was honestly surprising to me how slow it was.

Ultimately, it is the decision of the programmer as to what is the right method to use. If you want the advantages of templating as far as seperation of concerns and ease of maintenance and you have the ability, Blitz is probably a good choice for you. If you still want the ease of maintenance and separation of concerns provided by templating and are willing to make the tradeoff for a massive loss of speed, Smarty is a possibility also. If sheer pure speed is your primary concern and you’re not willing to make any kind of tradeoffs, going with raw PHP is probably your best option provided you fine tune it a bit to get the absolute best performance out of it.

16 Responses to “PHP Templating Celebrity Deathmatch!”

  1. alexey rybak Says:

    Hi, Rob!

    Thanx for the article, I’m blitz author and it was very nice to hear that blitz project was a subject of discussion at OSCON :)

    Well, I just wanted to put some notes on your benchmarking technique. Unfortunately things tend to change drastically when you have highload application in production (I work with applications run over hundreds servers). When code is complex and php apps have ~100 requests per secons many other interesting things come onto the scene. That’s why I prefer to use benchmarks a little bit closer to the real life (like lebowski benchmark mentioned in blitz documentation). And in a real world plain PHP mess with minimum of includes always wins. But development process without templating definitely sucks when you have ~100.000 lines code applications. So these are the real life conditions. AFAIK blitz beats all other template engines in this field. And that was my general purpose: to build a templating system wich doesn’t suck on high loads, and is smart enough to improve the development process.

  2. codelemur Says:

    Hi Alexey!

    Thanks for the comment and thanks for making Blitz available for me to play with! I’m always happy to see new projects in the PHP ecosystem - especially ones that show high-load promise.

    This was just a simple page generation time test, not just to test Blitz, but to verify what I have been told about Smarty (which had been my previous templating choice). Having seen the results from my little test, the benchmarks you have on the Blitz website make more sense to me. At some point, I may do a Part Deux! and do a load test across the three, though I really don’t see much of a reason to considering how badly Smarty did in the page generation test.

    Right now, I’m looking for an excuse to use Blitz. It’s too cool not to play with further now. :P

    P.S. You get mega bonus points for using examples from my favorite movie. I’ve got a Big Lebowski poster over my desk at the office. :P

  3. PHP Template tests « Ramblings of a web guy Says:

    [...] Rob did some simple tests to see how Blitz, Smarty and plain old PHP perform.  I thought some folks (hey Jay) might be [...]

  4. fred Says:

    Blitz has a template path config option somewhere like php.ini right? So why do you set a double standard for including absolute paths vs not between Blitz and raw php? You act like it’s a huge inconvenience in raw php to include absolute paths but it’s a matter of setting ONE constant and using it.

  5. codelemur Says:

    Fred,

    Hi, and thanks for the comments!

    I don’t think it’s a double-standard for the following reason: Blitz, by default, searches the current script path for the template and if it can’t find it simply throws an error, so I put the templates there. In further tests, I’ve discovered that you can call an absolute path or relative path from the Blitz class intantiation, though I haven’t tested the speed of this. PHP does the same thing in regards to including a file (as long as you have ‘.’ as the first line in your include_path), so I figured this was the fairest way to test the two. In that case, I actually gave PHP an edge when I tested it with an absolute path to the include, then it just matched Blitz in the simple test.

    FWIW, I don’t believe Blitz has a template_path argument in the php.ini file, but I haven’t read the documentation thoroughly so I could be wrong.

    And yes, you could set one constant to speed up includes … in EVERY PHP file that needs to template, unless you want to set it in some kind of includable file, then we’re right back at the beginning - PHP’s speed of including files.

    Ultimately, it’s your decision as to what you want to use. :P

  6. codelemur Says:

    As an addendum to the previous post, Brian tells me that you can define an environment variable from outside PHP (such as in the Apache configs) that will be available to all scripts running under that config.

    I had forgotten that you can do that, so I suppose that would be a solution to the aforementioned problem in the previous post. In that case, you could define in your local apache config a template_path constant and prepend that before each call. Still seems like a hoop to me when it’s easy to call “new Blitz(’template.tpl’);” vs “include TEMPLATE_PATH.”/template.tpl.php”;”

    But like I said, it’s all up to you. :P

  7. Top English WP Blogs « KHỦNG LONG IT Says:

    [...] PHP Templating Celebrity Deathmatch! Tags: php, smarty, blitz, includes, benchmarks Ladies and Gentleman! Welcome to the PHP Templating Celebrity […] [...]

  8. developercast.com » Brian Moon’s Blog: PHP Template tests (and Blitz) Says:

    [...] Tests were even done to compare it to several of the other popular templating frameworks currently offered.   [...]

  9. developercast.com » Rob Peck’s Blog: PHP Templating Celebrity Deathmatch! Says:

    [...] Code Lemur blog (as penned by Rob Peck) has a new post - a “deathmatch” for two of the PHP-associated templating solutions out there in a [...]

  10. Undefined variable » Blog Archive » PHP Templating Celebrity Deathmatch! Says:

    [...] Good article on comparison between Smarty and  Blitz. [...]

  11. mudkicker.com » Template Engines... Says:

    [...] before using it, I recommend all of my readers to read this blog entry written by Rob [...]

  12. alexey rybak Says:

    >> You get mega bonus points for using examples from my favorite movie
    oh dude you too ;)

  13. Ryan Says:

    I just installed this on our server and started testing some simple includes and basic variables for an aplication we are writing. So far I am very happy with the ease it was installed, the ease in which you can get started and the performance. I was using a very lightweight templating solution and this one blows it away. Great Job!

    My comment would be in regards to the template file path. I would love to be able to set an absolute path in the php.ini file or set a custom include path via php. This would save a ton of time overall in large implementations from writing:

    $tpl = new Blitz(’ui/html/login.tpl’);

    to just:

    $tpl = new Blitz(’login.tpl’);

    I could set the constant as referenced above but that really doesn’t save me anything.

    Keep up the great work!

  14. codelemur Says:

    Hi Ryan!

    Thanks for the comments!

    I didn’t actually write Blitz; that would be Alexey in the comments above. I just tested it. :P

    However, what you are wanting to do, if it’s not possible in the Blitz documentation, could easily be accompished by extending the Blitz class and overriding the constructor. You could define a template path, then do something like this:

    define(TEMPLATE_PATH,”/path/to/template/”);

    class tpl extends Blitz {
    function __construct($tpl) {
    parent::__construct(TEMPLATE_PATH.$tpl);
    }
    }

    Of course, in doing this you are adding additional overhead that will affect the speed of Blitz.

    Cheers!

  15. Alexey Rybak Says:

    >>I would love to be able to set an absolute path in the
    >>php.ini file or set a custom include path via php
    I have this in my todo and will add this very soon.
    http://alexeyrybak.com/blitz/bt/view.php?id=64
    Feel free to submit requests/bugs to the bugtracker.

  16. Panu Says:

    It would be nice to know how for example eaccelerator affects the results. Also if all comments are removed from the smarty class file it get’s slightly faster to initialize (or that is what the legend tells :)

    It’s true though that a php extension written in C is always going to be at least a little bit more efficient than similar PHP code.

Leave a Reply