Создание простого, но гибкого движка шаблонов

#php #regex #templating-engine

#php #регулярное выражение #движок для создания шаблонов

Вопрос:

Я пытаюсь создать базовый движок для создания шаблонов. Подобно движкам шаблонов, уже доступным с открытым исходным кодом, я использую методы поиска и замены.

Однако, поскольку поиск и замена должны быть жестко запрограммированы, это не настолько гибко. Я хочу сказать, что в качестве примера я использую что-то вроде этого

 $templateMarkup = '<div class="title">{_TITLE_}</div>';
$renderedMarkup = str_replace("{_TITLE_}",$title,$templateMarkup);
echo $renderedMarkup;
  

Как вы можете видеть, он жестко запрограммирован. Поэтому я должен намеренно знать все заполнители, чтобы выполнить успешный рендеринг.

Я немного слаб в регулярных выражениях. Но я знаю, что если я смогу разработать регулярное выражение, которое может сопоставлять весь текст, начинающийся с {_ и заканчивающийся _} , и получать значение между ними, я просто смогу создать гибкий механизм создания шаблонов.

Мне нужна помощь с регулярным выражением.

Если я иду совершенно неправильным путем, пожалуйста, предупредите меня.

Для тех, кто думает, что я изобретаю велосипед. Вот мое объяснение

 Templating engines, that are already available are quite unnecessarily complex. 
My requirements are simple and so I am builidng my own simple engine. 
  

Комментарии:

1. Вы уверены, что вам нужно написать свой собственный движок? Там нет ничего, что соответствовало бы вашим потребностям? Я имею в виду, зачем изобретать велосипед?

2. Я подумал, что мне нужно что-то добавить по этому поводу, прежде чем я это опубликую. Но причина в том, что существующие движки для создания шаблонов не обязательно сложны. Мои требования просты, и поэтому я создаю свой собственный простой движок.

3. Не могли бы вы назвать конкретный способ, при котором существующий движок шаблонов не подходил бы для ваших целей? Он может делать больше, но это не значит, что он «слишком сложный» для вас. Вы можете просто использовать его базовым способом, не так ли?

4. @Nanne, я определенно мог бы, но почему бы не выполнять простые операции с помощью простого кода. Я не думаю, что было бы разумно, если бы я загрузил весь zend framework целиком на свой сервер и использовал его только для подключений к БД. Хотя, это можно сделать, не так ли, Нанне?

5. Вы могли бы, и, возможно, вам следует. В данном случае я бы сказал, что если вы хотите использовать движок шаблонов, используйте smarty или что-то в этом роде. Если вам по какой-либо причине нужно что-то более простое, просто используйте PHP (поскольку это сам движок шаблонов) в вашем html. Зачем делать сложную замену, если можно просто использовать $var систему PHP?

Ответ №1:

Регулярное выражение, которое вы ищете, это {_(w )_} , если теги вашего шаблона состоят только из одного слова. Вы бы использовали его примерно так:

 <?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;

?>
  

Вы увидите, что preg_match_all регулярное выражение окружено косыми чертами, это разделители.

Обновление: Если вы хотите расширить регулярное выражение за пределы отдельных слов, то будьте осторожны при использовании . , чтобы соответствовать любому символу. Лучше использовать что-то вроде этого, чтобы указать, что вы хотите включить другие символы: {_([w-_] )_} . [w-_] Означает, что он будет соответствовать буквенно-цифровым символам, дефисам или знакам подчеркивания.

(Возможно, кто-нибудь может объяснить, почему использование . может быть плохой идеей? Я не уверен на 100%).

Комментарии:

1. @Sam, я предполагаю, что это была бы опечатка. Содержал две ошибки. Я исправил ваш ответ. Спасибо за решения ( 1). Я могу создать свой обходной путь, используя это. Однако я все равно подожду, прежде чем приму это как ответ :).

2. @sam, как сопоставить что-либо внутри {_ и _} ?

3. Вы правы, это тоже нуждалось в повторении, но в PHP при использовании двойных кавычек "{_$m_}" и "{_".$m."_}" получается точно то же самое. Попробуйте!

4. Ну, использование двойных кавычек «{ $ m }» выдало ошибку неизвестной переменной $m_ .

5. Вы правы! Хорошее место. Я обновил свой ответ на другой ваш вопрос.

Ответ №2:

Если вы не пытаетесь ограничить то, что люди могут делать в шаблоне, и хотите контролировать, какую разметку они могут в него вносить, я бы рекомендовал PHP как довольно крутой язык шаблонов!

Если вы хотите придерживаться своего решения, вы могли бы сделать что-то вроде этого для управления заменами.

 $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;
  

Комментарии:

1. @James, это определенно чище, но я пытаюсь избежать любого количества жесткого кодирования.

2. Код изменен в соответствии с «более чистым» подходом, предложенным в моем первоначальном посте. Здесь всю работу выполняют две строки кода.

3. @Джеймс, я обновил твой ответ. И спасибо за вашу помощь ( 1)

4. Никаких проблем. Он отлично работал в версии 5.3.2, возможно, вы использовали более старую версию.

Ответ №3:

Я объединил решения, предоставленные Сэмом и Джеймсом, для создания нового решения.

  • Спасибо Sam за часть с регулярными выражениями
  • Спасибо James за часть о режиме массива str_replace() .

Вот решение:

 $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;
  

Комментарии:

1. Теперь, если кто-нибудь подскажет мне, как сопоставить все символы внутри скобок. Я пытался использовать /{_(.*)_}/ , но он неправильно соответствует.

2. Вам нужно исключить _ и {}, должно быть возможно с помощью [^_{}]* вместо .*