# How the PHP-DTS Custom Template Engine Parses and Renders .htm Template Files

> Discover how the PHP-DTS template engine parses and renders htm files by compiling custom syntax into PHP and caching results for faster loading.

- Repository: [Nemo Ma/phpdts](https://github.com/amarillonmc/phpdts)
- Tags: deep-dive
- Published: 2026-02-24

---

**The PHP-DTS template engine compiles custom `.htm` syntax into executable PHP by transforming tags like `{if}`, `{loop}`, and `{$var}` into native PHP constructs, caching the result in `gamedata/cache/` for direct inclusion on subsequent requests.**

The [amarillonmc/phpdts](https://github.com/amarillonmc/phpdts) repository implements a lightweight, self-contained template system that avoids external dependencies. This **PHP-DTS custom template engine** processes raw `.htm` files through a two-stage pipeline—first locating and validating templates, then parsing custom markup into standard PHP code that the server executes directly.

## Template Engine Architecture

The system centers on two core functions defined in the `include/` directory. The **`template()`** function in [`include/global.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/global.func.php) serves as the entry point, handling template selection and cache management. When compilation is required, it delegates to **`parse_template()`** in [`include/template.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/template.func.php), which performs the actual syntax transformation using regular expressions and callbacks.

## Step-by-Step Parsing Flow

### Template Resolution and Cache Validation

When a controller calls `template($file, $templateid, $tpldir)`, the engine first resolves the absolute path to the source `.htm` file (e.g., `./templates/nouveau/index.htm` according to the `phpdts` source). It then constructs a compiled cache path under `gamedata/cache/` that incorporates the template ID to support multiple skins. If the cached PHP file is missing or older than the source template, the engine triggers a full recompile before proceeding.

### Syntax Translation and Normalization

Inside `parse_template()`, the raw template content undergoes a series of ordered transformations to convert custom tags into native PHP constructs:

- **Language localization**: `{lang KEY}` becomes the corresponding string from the global `$lang` array via callback replacement (lines 29‑30 of [`include/template.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/template.func.php)).
- **Variable output**: `{$var}` or `{ $array['key'] }` transforms into `<?= $var ?>` with normalized array syntax (lines 34‑35).
- **Expression evaluation**: `{eval PHP_CODE}` rewrites to `<?php PHP_CODE ?>`, while `{echo EXPRESSION}` becomes `<?php echo EXPRESSION; ?>` (lines 45‑46 and 48‑49).
- **Control structures**: `{if CONDITION}`, `{elseif CONDITION}`, `{else}`, and `{/if}` map directly to standard PHP conditional blocks (lines 51‑57).
- **Loop constructs**: Both `{loop $array $item}` and `{loop $array $key $value}` generate `foreach` loops (lines 57‑63).
- **Template inclusion**: `{template other}` recursively includes `<? include template('other'); ?>` (lines 43‑44).
- **Constants**: `{CONST}` outputs via `<?= CONST ?>` (line 68).

The engine also strips unnecessary line breaks and tabs (lines 27‑28) and expands short `<?` tags to full `<?php` syntax for compatibility (lines 69‑72).

### File Compilation and Inclusion

Finally, the transformed PHP string is written to the cache path (e.g., [`gamedata/cache/index_2.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/cache/index_2.php)). Control returns to `template()`, which includes the compiled file via `include $compiled_file;` (lines 114‑122 of [`include/global.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/global.func.php)), executing the embedded PHP and streaming the resulting HTML to the browser.

## Core Source Files and Functions

The template system relies on these specific implementation files:

- **[`include/global.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/global.func.php)**: Contains the `template()` dispatcher (starting at line 90) that manages template directory resolution and cache validation.
- **[`include/template.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/template.func.php)**: Houses `parse_template()` (lines 8‑72) which executes the regex-based parsing logic.
- **`templates/default/` and `templates/nouveau/`**: Directories containing the raw `.htm` source files for different skins.
- **`gamedata/cache/`**: Runtime directory storing compiled PHP versions of templates (e.g., [`index_2.php`](https://github.com/amarillonmc/phpdts/blob/main/index_2.php) for template ID 2).

## Practical Implementation Example

The following pattern demonstrates typical usage within a page controller:

```php
define('IN_GAME', true);
require './include/global.func.php';

// Render using the "nouveau" skin (template ID 2)
include template('index', 2, './templates/nouveau');

```

This sequence:
1. Locates `./templates/nouveau/index.htm`.
2. Validates or creates [`gamedata/cache/index_2.php`](https://github.com/amarillonmc/phpdts/blob/main/gamedata/cache/index_2.php).
3. Includes the compiled PHP file, executing embedded `foreach` and `if` statements.
4. Streams the resulting HTML to the client.

## Summary

- The engine uses **two-stage processing**: `template()` for orchestration and `parse_template()` for syntax transformation.
- **Cache-first architecture** stores compiled PHP in `gamedata/cache/` to eliminate parsing overhead on repeat requests.
- **Custom tag syntax** including `{lang}`, `{loop}`, `{if}`, and `{template}` converts to native PHP constructs via regex replacement.
- **Recursive inclusion** supports modular template design through the `{template}` tag.
- All logic resides in [`include/global.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/global.func.php) and [`include/template.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/template.func.php), making the system lightweight and portable.

## Frequently Asked Questions

### Where does the PHP-DTS template engine store compiled templates?

Compiled templates are stored as PHP files in the `gamedata/cache/` directory. The filename includes the template ID (e.g., [`index_2.php`](https://github.com/amarillonmc/phpdts/blob/main/index_2.php) for template ID 2), allowing multiple skin variants to coexist without collision.

### How does the engine handle language localization in templates?

The parser recognizes `{lang KEY}` syntax and replaces it with the corresponding value from the global `$lang` array via a callback function. This occurs during the compilation phase in `parse_template()` at lines 29‑30 of [`include/template.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/template.func.php).

### Can I use PHP code directly inside .htm template files?

Yes. The `{eval PHP_CODE}` tag executes arbitrary PHP during compilation, converting to `<?php PHP_CODE ?>`. For simple output, use `{echo EXPRESSION}` which becomes `<?php echo EXPRESSION; ?>`. Both tags are processed before the final compiled file is written to disk.

### What happens if I modify a source .htm file after it has been compiled?

The `template()` function in [`include/global.func.php`](https://github.com/amarillonmc/phpdts/blob/main/include/global.func.php) compares timestamps between the source `.htm` file and the cached PHP version. If the source is newer, it automatically invokes `parse_template()` to regenerate the compiled file before inclusion.