PHP 7.4+ · Zero dependencies · Two classes
Templates that read like PHP, and run as PHP.
If you know PHP, you already know PurePlate: same rules, lighter syntax. Your templates compile once to the plain PHP you would have written by hand, and render ~2.4× faster than Twig.
How it works
Write. Compile. Render.
Three steps, nothing hidden. What you read in a template is exactly what runs.
1. Write
A template is HTML with three kinds of tags: {{ user.name }} prints, {% foreach items as item %} controls, {# … #} comments.
2. Compile
On first use, the template becomes a plain PHP file in the cache: user.name is $user->name, name|strtoupper is strtoupper($name). Line 14 stays line 14.
3. Render
Every render includes that PHP file, cached by OPcache. Nothing is interpreted at runtime. If something fails, the error points at your template file and line.
Example
Write this. Run plain PHP.
A page that greets a user and lists products, inside a layout. Write it with PurePlate, and compare with plain PHP, with Twig, and with what PurePlate actually runs.
page.tpl · PurePlate · 7 lines
{% extends "layout.tpl" %} {% block content %} <h1>Hello, {{ user.name|strtoupper }}!</h1> {% foreach items as item %} <li>{{ item.title }} — {{ item.price|number_format(2) }} €</li> {% endforeach %} {% endblock %}
page.php · plain PHP · 7 lines
<?php ob_start() ?> <h1>Hello, <?= htmlspecialchars(strtoupper($user->name), ENT_QUOTES) ?>!</h1> <?php foreach ($items as $item): ?> <li><?= htmlspecialchars($item->title, ENT_QUOTES) ?> — <?= htmlspecialchars(number_format($item->price, 2), ENT_QUOTES) ?> €</li> <?php endforeach ?> <?php $content = ob_get_clean() ?> <?php require 'layout.php' ?>
To know: escape every output by hand, wire the layout yourself with output buffering.
page.twig · Twig · 7 lines
{% extends "layout.twig" %}
{% block content %}
<h1>Hello, {{ user.name|upper }}!</h1>
{% for item in items %}
<li>{{ item.title }} — {{ item.price|number_format(2) }} €</li>
{% endfor %}
{% endblock %}
To know: Twig's own language and filter names, attributes resolved at runtime, 3 dependencies, PHP 8.1+.
cache · what PurePlate runs
<?php $_plate->extend("layout.tpl"); ?>
<?php $this->startBlock('content'); ?>
<h1>Hello, <?php echo htmlspecialchars((string)(strtoupper($user->name)), ENT_QUOTES); ?>!</h1>
<?php foreach ($items as $item): ?>
<li><?php echo htmlspecialchars((string)($item->title), ENT_QUOTES); ?> — …</li>
<?php endforeach; ?>
<?php $this->endblock(); ?>
To know: nothing. It is the plain PHP from the first card, escaped and wired for you.
Why PurePlate
Made for PHP developers.
Templates print data, loop, test, and reuse a layout. You need that to be safe, fast and readable, not a new programming language.
Nothing to learn
A bare word is a variable, the dot is ->, the pipe calls a function. Everything else is written as in PHP, because it is PHP.
Every PHP function is a filter
strtoupper, number_format, substr, count, your own functions: all available, no registration, no wrappers.
Errors point at your template
In a page, a layout or an include, the exception's getFile() and getLine() are the template file and line, not the cache.
Fast, and safe by default
~2.4× faster than Twig 3 on the same page. {{ … }} is always escaped with htmlspecialchars.
Compare
The comfort of Twig, the speed of plain PHP.
Twig brings its own language and resolves it at runtime. Plain PHP is fast but leaves escaping and layouts to you. PurePlate writes the plain PHP for you.
| Plain PHP | Twig 3.30 | PurePlate | |
|---|---|---|---|
| Expression language | PHP | Twig's own language | PHP, lighter syntax |
| Escaping | By hand, on every output | Automatic | Automatic |
| Layouts & blocks | By hand, with output buffering | Yes | Yes, any number of levels |
| Filters | Function calls | Registered by name | Any PHP function |
user.name | $user->name | Resolved at runtime | Compiled to $user->name |
| Render time (benchmark) | Not measured | 194 µs | 82 µs |
| Dependencies | None | 3 Symfony packages | None |
| PHP version | Any | 8.1+ | 7.4+ |
Scope
What PurePlate will never do
Two classes you can read in one sitting stay a library you can trust. PurePlate will not grow into another language.
- resolve attributes at runtime
- guess a getter behind a dot
- mix up arrays and objects
- invent its own expression language
- make you register a filter
- load plugins
- require a dependency
Get PurePlate
One command. Zero dependencies.
PHP 7.4 or higher, with the standard tokenizer extension. Run composer require michel/pure-plate and render your first template.