If you want clean templates in PHP without pulling in a full framework, Mustache is a great fit. It keeps logic out of views, which forces you to prepare data in PHP first and makes templates easier to scan later. Think of it as a small habit that prevents messy presentation code from creeping in. 💡
A minimal setup is straightforward: install a Mustache implementation, create a renderer, and pass a plain array as context. Keep your template focused on placeholders and sections, then shape everything in your controller/service layer. In Mustache, {{#items}} starts a section that automatically iterates each element in items, so the inner markup behaves like a loop body per row.
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php
require ‘vendor/autoload.php’; $mustache = new Mustache_Engine([ $context = [ echo $mustache->render(‘report’, $context); |
|
1
2 3 4 5 6 7 8 9 |
<h2>{{title}}</h2>
<ul> {{#items}} <li>{{name}}: {{value}}</li> {{/items}} </ul> {{#hasWarnings}} <p>Please review warning metrics.</p> {{/hasWarnings}} |
Gotcha #1: Mustache is logic-less on purpose. No complex conditionals, no inline calculations, and no arbitrary PHP in templates. If you feel stuck, that is usually a signal to move transformation logic into PHP before render. Gotcha #2: escaping behavior matters — {{value}} is escaped by default, while triple braces are unescaped. Only use unescaped output for trusted HTML; otherwise you can introduce XSS risk quickly. 🔐
|
1
2 3 4 5 6 7 8 |
<?php
$context = [ ‘safe’ => ‘<strong>Hello</strong>’, ‘unsafe’ => ‘<script>alert(1)</script>’, ]; $template = ‘{{safe}} | {{{safe}}} | {{{unsafe}}}’; |
Gotcha #3: naming drift between context keys and template variables can silently render blanks. I usually keep small view-model builders (or DTOs) so key names are consistent across pages. If you keep templates dumb, context explicit, and escaping intentional, PHP + Mustache stays simple and maintainable for a long time. 🎉