Обновление - Спасибо за все ответы. Этот Q становится грязным, поэтому я начал продолжение, если кому-то интересно.
Я собрал быстрый script для друга и наткнулся на действительно простой способ создания шаблонов в PHP.
В принципе, идея состоит в том, чтобы анализировать html-документ как строку heredoc, поэтому переменные внутри него будут расширены PHP.
Функция пересылки позволяет оценивать выражения и функции и вызовы статических методов внутри строки:
function passthrough($s){return $s;}
$_="passthrough";
Код для разбора документа внутри строки heredoc является смехотворно простым:
$t=file_get_contents('my_template.html');
eval("\$r=<<<_END_OF_FILE_\n$t\_END_OF_FILE_;\n");
echo $r;
Единственная проблема заключается в использовании eval
.
Вопросы
-
Может ли кто-нибудь подумать о способе делать такие шаблоны без использования
eval
, но без добавления парсера или тонны безумия регулярного выражения? -
Любые предложения по экранированию штриховых знаков доллара, которые не относятся к переменным PHP, без написания полного парсера? Означает ли проблема бродячих знаков доллара этот подход нежизнеспособным для "серьезного" использования?
Вот пример шаблона HTML-кода.
<script>var _lang = {$_(json_encode($lang))};</script>
<script src='/blah.js'></script>
<link href='/blah.css' type='text/css' rel='stylesheet'>
<form class="inquiry" method="post" action="process.php" onsubmit="return validate(this)">
<div class="filter">
<h2>
{$lang['T_FILTER_TITLE']}
</h2>
<a href='#{$lang['T_FILTER_ALL']}' onclick='applyFilter();'>
{$lang['T_FILTER_ALL']}
</a>
{$filter_html}
</div>
<table class="inventory" id="inventory_table">
{$table_rows}
<tr class="static"><th colspan="{$_($cols+1)}">
{$lang['T_FORM_HELP']}
</th></tr>
{$form_fields}
<tr class="static">
<td id="validation" class="send" colspan="{$cols}"> </td>
<td colspan="1" class="send"><input type="submit" value="{$lang['T_SEND']}" /></td>
</tr>
</table>
</form>
Зачем использовать шаблоны?
Было некоторое обсуждение того, нужно ли создавать шаблонный слой в PHP, что, по общему признанию, уже довольно хорошо подходит для шаблонов.
Некоторые быстрые шаблоны шаблонов полезны:
-
Вы можете управлять им
Если вы предварительно обрабатываете файл до его перехода к интерпретатору, у вас есть больше контроля над ним. Вы можете вводить материал, блокировать разрешения, очищать злоумышленный php/javascript, кэшировать его, запускать через шаблон xsl, что угодно.
-
Хороший дизайн MVC
Templating способствует разделению зрения от модели и контроллера.
При прыжке с тегами
<?php ?>
в вашем представлении легко становится ленивым и выполнять некоторые запросы к базе данных или выполнять другие действия с сервером. Используя метод, подобный вышеизложенному, только один оператор может использоваться для каждого блока (без точки с запятой), поэтому гораздо труднее попасть в эту ловушку.<?= ... ?>
имеют почти такую же выгоду, но... -
Короткие теги не всегда включены
... и мы хотим, чтобы наше приложение запускалось в различных конфигурациях.
Когда я изначально взламываю концепцию вместе, она начинается как один php файл. Но прежде чем он вырастет, я не доволен, если все php файлы не имеют только один <?php
в начале и один ?>
в конце, и предпочтительно все это классы, кроме таких, как контроллер, настройки, сервер изображений и т.д.
Мне не нужно много PHP в моих представлениях вообще, потому что дизайнеры запутываются, когда в Dreamweaver или что-то в этом роде, когда он видит что-то вроде этого:
<a href="<?php $img="$img_server/$row['pic'].png"; echo $img; ?>">
<img src="<?php echo $img; ?>" /></a>
Это достаточно сложно для программиста. Средний графический дизайнер никуда не денется. С этим гораздо легче справиться:
<a href="{$img}"><img src="{$img}" /></a>
Программист сохранил свой неприятный код из html, и теперь дизайнер может работать над своей магией дизайна. Ура!
Быстрое обновление
Принимая во внимание все советы, я думаю, что предварительная обработка файлов - это путь, а промежуточные файлы должны быть как можно ближе к обычной "php templating", при этом шаблоны являются синтаксическим сахаром. Eval все еще на месте пока я играю с ним. Поведение heredoc несколько изменило его роль. Я напишу позже и попытаюсь ответить на некоторые из ответов, но пока...
<?php
class HereTemplate {
static $loops;
public function __construct () {
$loops=array();
}
public function passthrough ($v) { return $v; }
public function parse_markup ($markup, $no_escape=null, $vars=array()) {
extract($vars);
$eot='_EOT_'.rand(1,999999).'_EOT_';
$do='passthrough';
if (!$no_escape) $markup=preg_replace(
array(
'#{?{each.*(\$\w*).*(\$\w*).*(\$\w*).*}}?#',
'#{?{each.*(\$\w*).*(\$\w*).*}}?#',
'#{?{each}}?#',
'#{{#', '#}}#',
'#{_#', '#_}#',
),
array(
"<?php foreach (\\1 as \\2=>\\3) { ?>",
"<?php foreach (\\1 as \\2) { ?>",
"<?php } ?>",
"<?php echo <<<$eot\n{\$this->passthrough(", ")}\n$eot\n ?>",
"<?php ", " ?>",
),
$markup);
ob_start();
eval(" ?>$markup<?php ");
echo $markup;
return ob_get_clean();
}
public function parse_file ($file) {
// include $file;
return $this->parse_markup(file_get_contents($file));
}
}
// test stuff
$ht = new HereTemplate();
echo $ht->parse_file($argv[1]);
?>
...
<html>
{{each $_SERVER $key $value}
<div id="{{$key}}">
{{!print_r($value)}}
</div>
{each}}
</html>