Skip to content
Mikhail Deynekin edited this page Oct 11, 2026 · 5 revisions

HTML.PHP 🧩⚑

Version PHP Dependencies Tests PHPStan License

The production template engine for PHP that fits on a single file: template processing + full Apache SSI + gettext i18n + WordPress maintenance toolkit β€” with zero dependencies, zero globals and escaping on by default.

$engine = HtmlPhp\Engine::create(['templates' => ['paths' => [__DIR__ . '/tpl']]]);
echo $engine->render('page.html', ['title' => 'Hello <World>']);   // auto-escaped ✨

Why HTML.PHP exists

Shared hosting without Composer. Apache SSI directives that must keep working behind PHP. Legacy html4.pl template trees. WordPress sites that need translation audits and cache tooling. Tenants in one process that must not share state. Most template engines solve one of these; HTML.PHP solves all of them with one immutable Config, one DI Container and no $GLOBALS anywhere in the core β€” enforced by a token-level test in CI.

πŸ“– New here? Start with the Problem Domain analysis, then Getting Started. The full story: Architecture.

Feature matrix

Area What you get
🧩 Templates %{var|filters} (57 built-ins), inline expressions %{= a / b * 100} with nested/dynamic keys (rows[0].name, prices[currency], get(fieldName)), loops Γ—4 forms, expression @If/@Elif/@Unless, @Set, layout inheritance (@Extends/@Section/@SectionParent), scoped partials (@Include … with/only/ignore-missing), @Raw, @Comment, @Break/@Continue
🌐 Apache SSI #config #set #include(stub,wait) #echo(encoding) #if/#elif/#else #exec(policy-gated) #fsize #flastmod #printenv #block/#endblock + custom directive registry
πŸ—£οΈ i18n PO/MO/JSON/PHP catalogues, plural rules for 60+ languages, contexts, domains, fallback chains, Accept-Language negotiation, @Trans blocks, POT extraction + audit CLI, locale-aware number/date formats
πŸ”’ Security auto-escape ON, path containment + extension deny-lists, #exec deny-by-default, whitelisted expressions (no eval), syntax.expressions kill switch, dynamic keys that can never reach object properties, resource budgets on every recursion and on memos/iterators
πŸ”Œ WordPress (optional) bridge + plugin, shortcodes, theme template loader, object-cache/transient backend, rotating logs, admin screen, wp htmlphp CLI, maintenance toolkit Γ—12
πŸ› οΈ Operations template linter (25 codes, CI exit codes, JSON), render cache (file/APCu/array/null/WP/PSR-16), RenderStats profiling, diagnostics collector, PSR-3-shaped logging, events
πŸ“¦ Distribution single-file bundles php83/html.php & php85/html.php (no Composer needed) and PSR-4 source; PHPStan-clean; 386-test matrix across PHP 8.3/8.4/8.5 (with and without ext-intl)

Two editions

Edition File PHP Extras
8.3 portable php83/html.php 8.3 – 8.5+ typed constants, readonly, enums
8.5 modern php85/html.php 8.5+ pipe operator |>, array_find(), property hooks, asymmetric visibility, #[\NoDiscard]

Identical API & behaviour β€” both pass the same test matrix. Built from one source tree by tools/build.php with a CI drift gate.

By the numbers

Tests / assertions 386 / 1286 β€” CI matrix: PHP 8.3Β·8.4Β·8.5 Γ— srcΒ·php83Β·php85 Γ— intl on/off (14 jobs)
Static analysis PHPStan level 6, [OK] No errors β€” phpstan-baseline.neon is empty by policy (findings are fixed in code, never ignored)
Throughput (bench, PHP 8.3) ~1 400 full renders/s (50-row loop + SSI + i18n) Β· 69 k simple renders/s Β· 626 k t()/s
Runtime dependencies none (mbstring/intl/apcu enhance when present)
Bundle size ~510 KB single file

Navigate this wiki

πŸš€ Start here

πŸ“š Deep dives

πŸ“– Reference

🧭 Project


Tip

Every wiki page pairs with a canonical doc in the repository (docs/) β€” the wiki is the tutorial & reference layer, the repo docs are the versioned contract.

Clone this wiki locally