Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# An up-to-date Smarty V4.3.5 versus Twig V3.8.0 benchmark [19 February 2024]
# An Smarty versus Twig benchmark

An *opinionated* comparison benchmark of the latest versions of Smarty v4 and Twig v3.

TL;DR: Smarty is slower than Twig, Twig is faster than Smarty. Don't trust benchmarks from years ago.
An *opinionated* comparison benchmark of the latest versions of Smarty v5 and Twig v3.

## Opinionated How?

Expand All @@ -13,14 +11,6 @@ The main differences from other benchmarks you might run into:
XSS trouble.
* Doing a benchmark that _disables auto-escaping_ can hide performance problems in a part of the template engine you
*definitely* want to be using.
* This test is being performed in 2017, which means we're not even going to bother with PHP5
* A *lot* of things are different in PHP now, for example, objects have better performance characteristics in PHP 5.4+ (https://gist.github.com/nikic/5015323)

Most other benchmarks I've seen date from around 2011 or 2012. That's ancient in web-development terms. And unfortunately,
I've seen a few PHP coders get caught out, choose Smarty because "it's faster" (or so says one benchmark), and end up without
escaping throughout their templates.

Yes, authors should probably know to escape their output. But, equally, a single oversight shouldn't result in a vulnerability.

## Templates

Expand All @@ -35,19 +25,23 @@ The test templates are pretty simple:
Don't take my word for it:

* `composer install`
* `php bench.php smarty` or `php bench.php twig` or `php bench.php twig_reuse`
* `php bench.php smarty`, `php bench.php smarty_reuse`, `php bench.php twig` or `php bench.php twig_reuse`

Or, if you want to change the number of iterations (defaults to 100.000):

* `php bench.php smarty 42`, `php bench.php smarty 999999`

## Results

With Smarty 4.3.5 and Twig 3.8.0, on PHP 8.3, 100000 iterations, compile time ignored, cache warmed, my machine, best time
of dozens of runs each:
With Smarty 5.4.0 and Twig 3.11.0, on PHP 8.3, 1.000.000 iterations, compile time ignored, cache warmed, my machine:

Benchmark | Time Taken
--- | ---
twig | 1.0 seconds
twig_reuse | 0.8 seconds
smarty | 1.7 seconds
| Benchmark | Time Taken |
|--------------|-------------|
| twig | 9.2 seconds |
| twig_reuse | 8.5 seconds |
| smarty | 9.5 seconds |
| smarty_reuse | 8.8 seconds |

See the code for the difference between the twig and twig_reuse scenarios (basically: using the same Twig_TemplateWrapper instance, versus
loading the template again. I'm not sure there's an equivalent for Smarty, but I'd be happy to include one if there is.)
See the code for the difference between the normal and reuse scenarios (basically: using the same Template instance, versus
loading the template again.)

47 changes: 31 additions & 16 deletions bench.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

require __DIR__ . '/vendor/autoload.php';

function benchmark(string $type, int $iterations = 100000)
function benchmark(string $type, int $iterations)
{
echo 'Benchmarking ' . $type . "\n";

Expand Down Expand Up @@ -37,25 +37,34 @@ function setup($type)
{
switch ($type) {
case 'smarty':
$smarty = new Smarty();
$smarty->escape_html = true;
$smarty->compile_check = false;
$smarty = new Smarty\Smarty();
$smarty->setEscapeHtml(true);
$smarty->setCompileCheck(false);
$smarty->setCacheDir(__DIR__ . '/cache');
$smarty->setCompileDir(__DIR__ . '/cache');
return $smarty;

case 'smarty_reuse':
$smarty = new Smarty\Smarty();
$smarty->setEscapeHtml(true);
$smarty->setCompileCheck(false);
$smarty->setCacheDir(__DIR__ . '/cache');
$smarty->setCompileDir(__DIR__ . '/cache');
return $smarty->createTemplate('index.html.smarty');

case 'twig':
$loader = new \Twig\Loader\FilesystemLoader('templates');
return new \Twig\Environment($loader, [
'cache' => __DIR__ . '/cache',
]);
$loader = new \Twig\Loader\FilesystemLoader('templates');

return new \Twig\Environment($loader, [
'cache' => __DIR__ . '/cache',
]);

case 'twig_reuse':
$loader = new \Twig\Loader\FilesystemLoader('templates');
$env = new \Twig\Environment($loader, [
'cache' => __DIR__ . '/cache',
]);
$loader = new \Twig\Loader\FilesystemLoader('templates');

$env = new \Twig\Environment($loader, [
'cache' => __DIR__ . '/cache',
]);

return $env->load('index.html.twig');
default:
Expand All @@ -67,9 +76,14 @@ function benchmarkOnce($type, $instance, $data)
{
switch ($type) {
case 'smarty':
/** @var Smarty $instance */
/** @var Smarty\Smarty $instance */
$instance->assign($data);
return $instance->fetch('index.html.smarty');
case 'smarty_reuse':
/** @var Smarty\Template $instance */
$instance->assign($data);
return $instance->fetch();

case 'twig':
/** @var Twig_Environment $instance */
$template = $instance->load('index.html.twig');
Expand All @@ -87,4 +101,5 @@ function benchmarkOnce($type, $instance, $data)
exec('mkdir cache');

$type = $argv[1] ?? null;
benchmark($type);
$iterations = (int) ($argv[2] ?? 100000);
benchmark($type, $iterations);
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"description": "Benchmark of Smarty versus Twig",
"type": "project",
"require": {
"smarty/smarty": "^4.3",
"twig/twig": "^3.8"
"smarty/smarty": "^5.4",
"twig/twig": "^3.11"
},
"license": "MIT",
"authors": [
Expand Down