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 PHPTwig 3.30PurePlate
Expression languagePHPTwig's own languagePHP, lighter syntax
EscapingBy hand, on every outputAutomaticAutomatic
Layouts & blocksBy hand, with output bufferingYesYes, any number of levels
FiltersFunction callsRegistered by nameAny PHP function
user.name$user->nameResolved at runtimeCompiled to $user->name
Render time (benchmark)Not measured194 µs82 µs
DependenciesNone3 Symfony packagesNone
PHP versionAny8.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.