littlecat-team / xtscript-next
Independent, modern and extensible XtScript-compatible template engine for PHP 8.2+.
Requires
- php: ^8.2
This package is auto-updated.
Last update: 2026-08-06 01:56:00 UTC
README
Modern, extensible XtScript-compatible template engine for PHP 8.2+
littlecat-team/xtscript-next combines backward-compatible XtScript/XtGem syntax with a modular Composer architecture, default-context escaping, and a typed compilation pipeline. It draws design inspiration from Twig and Blade while preserving the practical template language that XtGem developers already know.
Installation
Use Composer to require the package:
composer require littlecat-team/xtscript-next
If you need to use the current Git repository directly, configure it as a VCS repository in composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/littleCatTeam/XtScript-Next-PHP"
}
]
}
Zero dependencies beyond PHP 8.2. No extensions required.
Quick start
use XtScript\Engine; use XtScript\Loader\FilesystemLoader; $engine = new Engine(new FilesystemLoader(__DIR__ . '/templates')); echo $engine->render('page', [ 'name' => 'World', 'items' => ['one', 'two', 'three'], ]);
Template (templates/page):
print Hello $name
foreach $items as $item
print - $item
endforeach
print auto-escapes HTML by default. Use print_raw or the raw filter when raw output is intended.
Features
Compatibility
- Full backward compatibility with historical XtScript/XtGem syntax —
assign,print,if/foreach,include,call,goto, legacy{{ }}multiline values,@functionaliases, and<!--parser:xtscript-->wrappers.
Modern template primitives
- Template inheritance (
extends/block/parent) & components (component/slot) - Function imports with namespacing (
import/as) - Stacks (
push/prepend/stack),verbatim,capture,cache,once,with,do,apply - Lexical scopes (
autoescape,beautify,minify) - Custom block tags and configurable XT tag prefixes
Expressions & filters
- Rich expression engine: comparisons, logic, arithmetic, ternary, null-coalescing,
matches/not matches,in/not in, array/map literals, dotted access - Built-in string, math, collection, date, regex, and formatting filters
- Filter pipelines and tests (
is defined,is empty,is even, …)
Regex
- Full PCRE2 patterns through
/pattern/modifiers matches/not matchesoperators, capture groups,replace,split,grep,quote,count
Safety by default
- Default HTML escaping on
print - Plugable
SecurityPolicyInterface(allow-list functions, filters, tags, templates) - Source, instruction, time, output, context, loop, depth, capture, and stack budgets
- Canonical filesystem root enforcement — symlink and traversal protection
Performance
- Templates compile to typed
Program/Instructionobjects - In-process L1 cache with source-change invalidation + optional persistent L2 cache
- Conservative PHP-eval fast path for eligible templates (~1.1× the portable evaluator)
- Optional AOT PHP-file backend (
ExecutionBackend::PhpFile) with OPcache reuse - Single plugin/filter/test/tag registry built at setup time — zero discovery on the hot path
Extensibility
PluginInterface— register functions, filters, tests, tags, block tags, XT tags, and globalsLoaderInterface— filesystem, array, database, Redis, API, or custom loaders- Optional
ProfilerInterface,FragmentCacheInterface,CookieStoreInterface
Tooling
- CLI:
vendor/bin/xtscript—lint,deps,inspect,compile,warmup,benchmark,beautify,minify Engine::dependencies()exposes the static template dependency graphTemplateContractfor typed host-context validation- Context-selectable escaping strategies (HTML, JS, CSS, URL)
Architecture
Template source
↓
LoaderInterface — Filesystem / Array / DB / Redis / API / custom
↓
Parser → Program / typed Instructions → L1/L2 compiled-program cache
├── conservative PHP fast path (eligible programs only)
│ └── generated closure cached per Program
└── portable Evaluator fallback
├── Context / scopes / globals
├── RuntimeState / execution budgets
├── functions / filters / tests / tags / block tags / XT tags
├── inheritance / components / imports / stacks
├── optional fragment cache
└── optional SecurityPolicyInterface
The PHP fast path emits code only from the validated typed instruction tree — raw template source is never concatenated as executable PHP. Unsupported programs automatically fall back to the evaluator. When a SecurityPolicyInterface is configured, the evaluator is always used.
Syntax overview
| Category | Commands |
|---|---|
| Output | print, print_raw |
| Variables | assign / var, get, get_or_default, delete / del |
| Control flow | if/elseif/else/endif, foreach/endforeach, for/endfor, switch/case/endswitch, break, continue |
| Functions | function/endfunction, call, return, import/as |
| Templates | include, extends/block/parent, component/slot |
| Scopes | autoescape, capture, cache, with, do, once, apply, beautify, minify, verbatim |
| Stacks | push, prepend, stack |
| Legacy | goto/@labels, <!--parser:xtscript-->, {{ multiline }} |
See docs/syntax.md for the full reference.
Documentation
| Topic | Link |
|---|---|
| Getting started | docs/getting-started.md |
| Syntax reference | docs/syntax.md |
| Core functions & filters | docs/core-functions.md |
| Plugins | docs/plugins.md |
| Configuration | docs/configuration.md |
| Security | docs/security.md |
| CLI tools | docs/cli.md |
| Architecture | docs/architecture.md |
| Regex | docs/regex.md |
| Escaping & formatting | docs/escaping.md, docs/formatting-assets.md |
| Tests | docs/tests.md |
Runnable examples are indexed in examples/README.md.
Development
php -n tests/lint.php # Syntax check (102 files) php -n tests/run.php # Unit tests (117 scenarios) php -n tests/reflection.php # Strict type audit php -n tests/fuzz.php # Randomized parser fuzzing (3000 inputs)
PHAR package
Build a release PHAR from the repository:
php -d phar.readonly=0 build-releases.php 1.0.0
If your repository is tagged, build-releases.php can infer the version from the latest tag:
php -d phar.readonly=0 build-releases.php
This generates xtscript-v1.0.0.phar in the current directory.
You can also download xtscript-v1.0.0.phar directly from the GitHub release assets instead of building it locally.
Run the packaged PHAR directly:
php xtscript-v1.0.0.phar [command] [args]
Example commands:
php xtscript-v1.0.0.phar lint templates/ php xtscript-v1.0.0.phar deps templates/ page php xtscript-v1.0.0.phar inspect templates/ page php xtscript-v1.0.0.phar compile templates/ cache/ php xtscript-v1.0.0.phar warmup templates/ cache/ php xtscript-v1.0.0.phar benchmark templates/ page 100
If the file is executable, you can also run:
chmod +x xtscript-v1.0.0.phar ./xtscript-v1.0.0.phar lint templates/
For help, use:
php xtscript-v1.0.0.phar help
Use the PHAR as a library
You can also require the PHAR from a PHP script without Composer:
require 'xtscript-v1.0.0.phar'; use XtScript\Engine; use XtScript\Loader\FilesystemLoader; $engine = new Engine(new FilesystemLoader(__DIR__ . '/templates')); echo $engine->render('page', ['name' => 'World']);
php benchmarks/render.php # Cache behavior php benchmarks/backends.php # Evaluator vs PHP fast path
Exceptions
All errors derive from XtScript\Exception\XtScriptException:
SyntaxErrorExceptionTemplateNotFoundExceptionPluginExceptionSecurityException
License
MIT. Copyright © littleCatTeam.