I'm designing a simple templating system for a CMS in PHP which internally currently uses something like:
require_once 'templates/template1.php`;
to import the desired template.
I would like every content {{field123}}
in this PHP file to be automatically converted into <?php echo $row['field123']; ?>
before being passed into require_once
and executed by PHP.
Is there a way to activate a preprocessor (I know that PHP is already named after preprocessor) that does this replacement {{anything}} -> <?php echo $row['anything']; ?>
before executing the PHP code template1.php
? If not, what's the usual way to do this?
Having PHP code in templates - especially code with potential side-effects - can get dirty real quick. I would recommend using static templates, treating them as strings instead of executing them, then parsing them for tokens, with your main application compiling them and handling output.
Here is a rudimentary implementation that parses variables into tokens, and also handles mapped function calls in your templates. First, "fetching" our template (for a simple example):
$tpl = 'This is a sample template file.
It can have values like {{foo}} and {{bar}}.
It can also invoke mapped functions:
{{func:hello}} or {{func:world}}.
Hello user {{username}}. Have a good day!';
Then, the template parser:
function parse_template(string $tpl, array $vars): string {
// Catch function tokens, handle if handler exists:
$tpl = preg_replace_callback('~{{func:([a-z_]+)}}~', function($match) {
$func = 'handler_' . $match[1];
if(function_exists($func)) {
return $func();
}
return "!!!What is: {$match[1]}!!!";
}, $tpl);
// Generate tokens for your variable keys;
$keys = array_map(fn($key) => '{{' . $key . '}}', array_keys($vars));
// Substitute tokens:
$tpl = str_replace($keys, $vars, $tpl);
return $tpl;
}
These are our handler functions, with handler_X
matching {{func:X}}
.
function handler_hello() {
return 'HELLO THERE';
}
function handler_world() {
return '@Current World Population: ' . mt_rand();
}
Then, here are the variables you'd like to parse in:
$vars = [
'foo' => 'Food',
'bar' => 'Barnacle',
'username' => 'Herbert'
];
Now let's parse our template:
$parsed = parse_template($tpl, $vars);
echo $parsed;
This results in:
This is a sample template file.
It can have values like Food and Barnacle.
It can also invoke mapped functions:
HELLO THERE or @Current World Population: 1477098027.
Hello user Herbert. Have a good day!
Job done. You really don't need a complicated templating engine for something like this. You could easily extend this to allow the handlers to receive arguments defined in the template tokens -- however I'll leave that for your homework part. This should do to demonstrate the concept.
As mentioned in a comment and in How do I capture PHP output into a variable?, the use of output buffering can work:
<?php
ob_start();
?>
Hello
{{field123}} and {{field4}}
World
<?php // or require_once 'template1.php'; ?>
<?php
$s = ob_get_clean();
$a = array('field123' => 'test', 'field4' => 'test2');
$s = preg_replace_callback('/{{(.*?)}}/', function ($m) use ($a) { return isset($a[$m[1]]) ? $a[$m[1]] : $m[0]; }, $s);
echo $s;
?>
// Output:
// Hello
// test and test2
// World
Here we also used a method similar to Replace with dynamic variable in preg_replace to do the replacement.
Firebase Cloud Functions: PubSub, "res.on is not a function"
TypeError: Cannot read properties of undefined (reading 'createMessageComponentCollector')
I have a custom cursor div which changes when hovering over various elementsSo far, I have the cursor expanding on hover of
everyone so I have been working on a Bidding Bot to make Offers on Assests of a Collection on Openseaio
I have a batch with many jobs almost over 9,000 and the first of them consumed by workers always get 1205 "Lock wait timeout exceeded" errorsI have submitted an issue on GitHub but it was closed so I'm asking for help here