Creating a simple but flexible templating engine
I am trying to build a basic templating engine. Like the template engines already available as open source, I am using search and replace techniques.
However, as the search and replace have to be hardcoded, it is not so much flexible. What I mean to say is, as an example, I am using something like this
$templateMarkup = '<div class="title">{_TITLE_}</div>';
$renderedMarkup = str_replace("{_TITLE_}",$title,$templateMarkup);
echo $renderedMarkup;
开发者_开发百科As you can see, it is hardcoded. So I have to purposely know all the placeholders to accomplish a successful render.
I am a little bit weak in regular expression. But I know, if I can develop a regex, which can match all the text starting with {_
and ending _}
and get the value in between them, I just might be able to create a flexible templating engine.
I need help with the regular expression.
If I am completely going the wrong way to accomplish, please do warn me.
For those who think I am reinventing the wheel. Here is my explanation
Templating engines, that are already available are quite unnecessarily complex.
My requirements are simple and so I am builidng my own simple engine.
The regular expression you're looking for is {_(\w+)_}
, if your template tags are only ever a single word. You'd use it a bit like this:
<?php
$replacements = array(
"firstname" => "John",
"lastname" => "Smith"
);
$template_markup = "Hello {_firstname_} {_lastname_}";
if(preg_match_all('/{_(\w+)_}/', $template_markup, $matches)) {
foreach($matches[1] as $m) {
$template_markup = str_replace("{_".$m."_}", $replacements[$m], $template_markup);
}
}
echo $template_markup;
?>
You'll see the preg_match_all
has forward slashes surrounding the regular expression, these are delimiters.
Update: If you want to expand the regular expression beyond single words, then be careful when using .
to match any character. It's better to use something like this to specify that you want to include other characters: {_([\w-_]+)_}
. The [\w-_]
means it will match either alphanumeric characters, hyphens or underscores.
(Perhaps someone can explain why using .
might be a bad idea? I'm not 100% sure).
Unless you're trying to restrict down what people can do within a template and want to control what markup they can put in it I'd recommend PHP as a pretty kick-ass templating language!
If you want to stick with your solution you could do something like this to manage replacements.
$template = "foo={_FOO_},bar={_BAR_},title={_TITLE_}\n";
$replacements = array(
'title' => 'This is the title',
'foo' => 'Footastic!',
'bar' => 'Barbaric!'
);
function map($a) { return '{_'. strtoupper($a) .'_}';}
$keys = array_map("map", array_keys($replacements));
$rendered = str_replace($keys, array_values($replacements), $template);
echo $rendered;
I have combined the solutions provided by both Sam and James to create a new solution.
- Thanks to
Sam
for the regex part - Thanks to
James
for the array modestr_replace()
part.
Here is the solution:
$replacements = array(
"firstname" => "John",
"lastname" => "Smith"
);
function getVal($val) {
global $replacements;
return $replacements[$val];
}
$template_markup = "Hello {_firstname_} {_lastname_}";
preg_match_all('/{_(\w+)_}/', $template_markup, $matches);
$rendered = str_replace($matches[0], array_map("getVal",array_values($matches[1])), $template_markup);
echo $rendered;
精彩评论