Search by

sailantis / clarity-engine

lumielis

A fast and powerful Template engine for PHP inspired by Twig.

Package info

github.com/sailantis/clarity-engine

pkg:composer/sailantis/clarity-engine

Statistics

Installs: 24

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-09-28 20:16 UTC

This package is auto-updated.

Last update: 2026-09-28 22:44:45 UTC


README

Clarity Logo

A fast, secure, and expressive PHP template engine – Clarity compiles .clarity.html templates into cached PHP classes for maximum performance while maintaining a sandboxed, secure execution environment.

Features

  • Compiled & Cached – Templates compile to PHP classes and leverage OPcache for blazing-fast rendering
  • Secure Sandbox – No arbitrary PHP execution by default; templates are strictly sandboxed with controlled access
  • Opt-In Open Mode – Disable the sandbox to give templates the full power of PHP (any function call or filter, method calls, {% php %} blocks) — Blade / Stempler / Plates parity, for trusted authors
  • Expressive Syntax – Clean, readable template syntax inspired by modern template engines
  • Twig-Style Tests – in, is defined, starts with, matches, divisible by, and more, with absence-tolerant defined/null/empty
  • Whitespace Control – {%- … -%} trims whitespace around a tag
  • Loop Fallbacks – {% for %} … {% else %} … {% endfor %} renders the else branch when the sequence is empty
  • Template Inheritance – Reusable layouts with extends and blocks for DRY template architecture
  • Macros – Define reusable template fragments with parameters and call them inline
  • Extensible — Custom filters, functions, inline filters, block directives, and loader plugins
  • Modules – Bundle filters, functions, and directives into self-registering plug-ins
  • Auto-escaping – Built-in XSS protection with context-aware automatic HTML/JS/CSS escaping
  • Unicode Support – Full multibyte string handling with transparent normalization
  • Zero Dependencies – Standalone engine with no external dependencies beyond PHP 8.1+

Installation

composer require sailantis/clarity-engine

Requirements: PHP 8.1 or higher

Quick Start

Basic Setup

<?php
require_once 'vendor/autoload.php';

use Clarity\ClarityEngine;

// Initialize the engine
$engine = new ClarityEngine([
    'viewPath'   => __DIR__ . '/templates',
    'namespaces' => [
        'admin'  => __DIR__ . '/templates/admin',
        'emails' => __DIR__ . '/templates/emails',
    ],
]);

// Render a template
echo $engine->render('welcome', [
    'title' => 'Welcome to Clarity',
    'user' => ['name' => 'Developer'],
]);

Your First Template

templates/welcome.clarity.html:

<!DOCTYPE html>
<html>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
    <h1>Hello, {{ user:name }}!</h1>
    <p>The current time is {{ "now" |> date("H:i:s") }}</p>
  </body>
</html>

That's it! Clarity automatically compiles and caches your template.

Documentation

For Template Authors

Start here if you're writing templates:

For Developers

Integration and advanced topics:

Reference

Output & Variables

{{ expression }}                 {# Output with auto-escaping #}
{{ expression | raw }}           {# Output raw HTML (no escaping) #}
{{ expression |> raw }}          {# Same — both | and |> are filter pipes #}
{{ user:name }}                  {# Array key #}
{{ user.name }}                  {# Object property #}
{{ items[0] }}                   {# Array index #}
{{ user[var] }}                  {# Dynamic array key #}
{{ user{var} }}                  {# Dynamic property #}
{{ firstName ~ ' ' ~ lastName }} {# String concatenation #}

Control Flow

{% if condition %}...{% elseif other %}...{% else %}...{% endif %}

{% for item in items %}
  {{ item:name }}
{% endfor %}

{% for key, value in assocArray %}               {# Loop with key variable #}
  {{ key }}: {{ value }}
{% endfor %}

{% for i in 1..10 %}{{ i }}{% endfor %}          {# Range: 1 to 10 (inclusive) #}
{% for i in 1...10 %}{{ i }}{% endfor %}         {# Range: 1 to 9 (exclusive) #}
{% for i in 0..100 step 10 %}{{ i }}{% endfor %} {# With step #}

{% set total = items | length %}

Macros

{% macro @card(title, body) %}
<div class="card"><h3>{{ title }}</h3><p>{{ body }}</p></div>
{% endmacro %}

{% @card("Welcome", intro) %}
{% @card(article.title, article.excerpt) %}

Filters

{{ text | upper }}
{{ text |> upper }}                          {# both | and |> are equivalent #}
{{ price | number(2) }}
{{ timestamp | date('Y-m-d H:i') }}
{{ "Hello, %s!" | sprintf(user.name) }}
{{ tags | join(', ') }}
{{ users | map(u => u.name) | join(', ') }}  {# Lambda expression #}
{{ items | filter(i => i.active) | length }}
{{ title | slug }}                           {# URL-friendly slug #}
{{ html | striptags }}                       {# Strip HTML tags #}

Common filters: upper, lower, trim, length, number, date, sprintf, json, join, split, slug, map, filter, reduce, default, empty, striptags, escape, raw

See all filters and detailed syntax →

Template Inheritance

{# layouts/base.clarity.html #}
<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}Default Title{% endblock %}</title>
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>

{# pages/home.clarity.html #}
{% extends "layouts/base" %}
{% block title %}Home Page{% endblock %}
{% block content %}
  <h1>Welcome!</h1>
{% endblock %}

Includes

{% include "partials/header" %}                {# Static include #}
{{ include("widgets/card", { title: "Hi" }) }} {# Dynamic include with context #}

Full syntax reference →

Configuration

Configure the engine with these methods:

// Initialize with config array
$engine = new ClarityEngine([
    'viewPath' => __DIR__ . '/templates',
    'cachePath' => __DIR__ . '/cache',
]);

// Or configure via setters
$engine = ClarityEngine::create()
    ->setViewPath(__DIR__ . '/templates')
    ->setCachePath(__DIR__ . '/cache'); // Default: sys temp + /clarity_cache

// Additional configuration
$engine->setExtension('.tpl.html');           // Default: .clarity.html

// Register named namespaces (convenience method)
$engine->addNamespace('admin',  __DIR__ . '/templates/admin');
$engine->addNamespace('emails', __DIR__ . '/templates/emails');
// Templates with a namespace prefix: {% include "admin::sidebar" %}
// Unprefixed templates still resolve via the base viewPath.

// Namespaces can also be passed in the constructor:
// new ClarityEngine(['namespaces' => ['admin' => __DIR__ . '/templates/admin']]);

// For advanced multi-source setups, set a loader directly:
$engine->setLoader(new \Clarity\Template\DomainRouterLoader(
    ['admin' => new \Clarity\Template\FileLoader('/path/to/admin/templates')],
    fallback: new \Clarity\Template\FileLoader('/path/to/templates'),
));
$engine->setDebugMode(true);                  // Runtime safety checks (dev only)

// Add custom filter
$engine->addFilter('currency', fn($v) => '€ ' . number_format($v, 2));
// Clear compiled templates
$engine->flushCache();

// Modules: bundle filters, functions, and directives
$engine->use(new \Clarity\Localization\IntlFormatModule(['locale' => 'en_US']));
$engine->use(new \Clarity\Localization\TranslationModule([
    'locale'            => 'en_US',
    'translations_path' => __DIR__ . '/locales',
]));

Configuration guide →

Security

Clarity is sandboxed by default:

  • No arbitrary PHP execution – Templates cannot call PHP functions or access global state
  • Auto-escaping by default – All output is HTML-escaped to prevent XSS attacks
  • Compile-time validation – Syntax errors caught during compilation, not at runtime
  • Object safety – Objects stay objects: a.b reads a public property and a:b reads an array key, so method calls are unreachable from templates and PHP visibility rules apply. Container operations read an object's public properties, and the date filter accepts DateTimeInterface directly
  • Controlled lambdas – Lambda expressions can only use registered filters

PHP Mode

The sandbox can be disabled deliberately ("PHP mode"), granting templates the full power of PHP (any function call or filter, $obj->method(), and raw PHP through either {% php %}…{% endphp %} or the standalone {% php CODE %} form):

$engine->setSandboxMode(false);

PHP mode is intended for templates written by trusted authors. It is equivalent to executing arbitrary PHP and disables every guarantee listed above. Templates record which mode compiled them and are recompiled automatically when the setting changes. Nothing is blocked by default — PHP mode is the security decision; if you want extra guardrails, add them with setDeniedFunctions([...]).

Security best practices →

Performance

Clarity is designed for speed. Templates compile to native PHP classes and leverage OPcache for optimal performance:

  • Compiled templates – One-time compilation to PHP, then served from OPcache
  • Auto-invalidation – Cache automatically refreshed when templates change
  • Zero runtime overhead – Inheritance resolved at compile time
  • Minimal memory footprint – Efficient compilation with predictable memory usage

Benchmark Results

Clarity is measured against the other mainstream PHP template engines rendering the same page, on the same machine and PHP build. The two charts below are generated from the benchmark.

Per-render time

The dot is the median render and the caps bound the fastest observation and p95, so an engine that is usually fast but occasionally slow looks different from one that is uniformly slower.

Memory retained per run

Measured in a fresh process per engine, so no engine inherits another's footprint. The bar runs from the floor that engine costs to have loaded (left cap) to the peak it reached (right cap), and the dot is what it still holds once the run is done — the figure a serving process actually carries.

The full comparison — every shape, every chart, and the environment and engine versions this run recorded — is in the benchmark report, with the public version of the same data at https://sailantis.github.io/azera-competition/benchmarks/view-engine.html.

Performance optimization guide →

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Running Tests

composer install
composer test

Or run PHPUnit directly:

php vendor/bin/phpunit

License

This project is licensed under the MIT License - see the LICENSE file for details.

Links

Built with ❤️ for developers who value security and performance