Выношу на суд общественности мой вариант. Возможностей немного, необходимый минимум:
- подстановка значений
- подстановка значений с экранированием. (типа защита от внедренного кода)
- подстановка по индексу массива, размерность любая.
Жду злобных комментариев.
Сначала шаблон example.tpl:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><!– title –></title>
</head>
<body>
<p>Message: <!– message –></p>
<p>Code: <!– code –></p>
<p>Escaped code: <!– @code –></p>
Array access:
<ul>
<li>xarr['a']: "<!– xarr:a –>" - element</li>
<li>esc(xarr['a']): "<!– @xarr:a –>" - escaped element</li>
<li>xarr['b']['r']: "<!– xarr
r –>" - multidimentional</li>
<li>xarr['b'][12]: "<!– xarr
12 –>" - multidimentional, int key</li>
<li>xarr['c'][8]: "<!– xarr:c:x –>" - (wrong index)</li>
<li>xarr['d'][1]: "<!– xarr:d:1 –>" - array d is reference</li>
</ul>
</body>
</html>
Теперь сам парсер example.php
<?php
$arrByRef = array('alpha', '<b>b</b>eta', 'gamma');
$data = array(
'title' => 'The Example page',
'message' => 'Some text',
'code' => 'The <b>bold</b> text',
'xarr' => array(
'a' => 'AAA<u>UUU</u>BBB',
'b' => array(
'q' => 'B10',
'r' => 'B11',
12 => 'B12'),
'd' => &$arrByRef)
);
function htmlescape($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
function parseTemplate(&$data, $file)
{
// template is NOT php-script, read it as plain text
$text = file_get_contents($file);
// then if data provided, substitute placeholders
if (!is_null($data) && count($data))
{
// split to parts divided by "<!– key –>"
$arr = preg_split('/(<!–.*–>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
// … if any, process substitutions
if (count($arr) > 1)
{
$text = '';
foreach ($arr as $clause)
{
if (substr($clause, 0, 4) == '<!–')
{
// strip "<!–" and "–>"
$key = trim(substr($clause, 4, -3));
$escape = FALSE;
$success = TRUE;
if ($key{0} == '@')
{
$key = substr($key, 1);
$escape = TRUE;
}
if (strpos($key, ':') !== FALSE)
{
$keys = explode(':', $key);
$d =& $data;
foreach ($keys as $key)
{
if (isset($d[$key]))
$d = &$d[$key]; // iterate like chained list
else
{
$success = FALSE;
break;
}
}
if ($success)
$clause = $d;
}
else
{
if (isset($data[$key]))
$clause = $data[$key];
}
if ($success && $escape)
$clause = htmlescape($clause);
}
$text .= $clause;
}
}
}
echo $text;
}
parseTemplate($data, './example.tpl');
Update: ниже есть обновлённый вариант http://pyha.ru/forum/topic/2013.msg34213#msg34213
Update N: http://pyha.ru/forum/topic/2013.msg36109#msg36109
if-elseif-else, foreach, компиляция в PHP, модификаторы по типу {:var|str_repeat,3|strtolower}