Для группового проекта я пытаюсь создать механизм шаблонов для PHP для людей с меньшим опытом работы с языком, которые могут использовать теги, такие как {name} в своем HTML, и PHP заменит этот тег на предопределенную переменную из массива. А также поддерживающие петли.
Это намного превосходит ожидания проекта, но поскольку у меня есть опыт работы с PHP, я думал, что это будет хороший вызов, чтобы держать меня занятым!
Мои главные вопросы: как я могу сделать часть цикла парсера, и это лучший способ реализовать такую систему. Прежде чем просто рекомендовать существующую систему шаблонов, я бы предпочел создать ее самостоятельно для получения опыта и потому, что все в нашем проекте должно быть нашим.
На данный момент основной синтаксический анализ выполняется с помощью регулярных выражений и preg_replace_callback, он проверяет, существует ли $ data [name] и если он его заменяет.
Я попытался сделать цикл различными способами, но не уверен, что я на правильном пути!
Например, если данные, которые был предоставлен синтаксический анализатор, были:
Array ( [title] => The Title [subtitle] => Subtitle [footer] => Foot [people] => Array ( [0] => Array ( [name] => Steve [surname] => Johnson ) [1] => Array ( [name] => James [surname] => Johnson ) [2] => Array ( [name] => josh [surname] => Smith ) ) [page] => Home )
И страница, которую он обрабатывал, была чем-то вроде:
<html> <title>{title}</title> <body> <h1>{subtitle}</h1> {LOOP:people} <b>{name}</b> {surname}<br /> {ENDLOOP:people} <br /><br /> <i>{footer}</i> </body> </html>
Это создаст нечто похожее на:
<html> <title>The Title</title> <body> <h1>Subtitle</h1> <b>Steve</b> Johnson<br /> <b>James</b> Johnson<br /> <b>Josh</b> Smith<br /> <br /><br /> <i>Foot</i> </body> </html>
Ваше время невероятно ценится с этим!
Большое спасибо,
Ps Я полностью не согласен с тем, что, поскольку я ищу, чтобы создать нечто похожее на то, что уже существует для опыта, мой хорошо отформатированный и простой для понимания вопрос проголосовал.
Pps Кажется, есть огромное распространение мнений по этой теме, пожалуйста, не голосуйте, потому что у них другое мнение. Каждый человек имеет право на свое собственное!
Простым подходом является преобразование шаблона в PHP и его запуск.
$template = preg_replace('~\{(\w+)\}~', '<?php $this->showVariable(\'$1\'); ?>', $template); $template = preg_replace('~\{LOOP:(\w+)\}~', '<?php foreach ($this->data[\'$1\'] as $ELEMENT): $this->wrap($ELEMENT); ?>', $template); $template = preg_replace('~\{ENDLOOP:(\w+)\}~', '<?php $this->unwrap(); endforeach; ?>', $template);
Например, это преобразует теги шаблона во встроенные PHP-теги.
Вы увидите, что я сделал ссылки на $this->showVariable()
, $this->data
, $this->wrap()
и $this->unwrap()
. Это то, что я собираюсь реализовать.
Функция showVariable
показывает содержимое переменной. wrap
и unwrap
вызывается на каждой итерации для обеспечения закрытия.
Вот моя реализация:
class TemplateEngine { function showVariable($name) { if (isset($this->data[$name])) { echo $this->data[$name]; } else { echo '{' . $name . '}'; } } function wrap($element) { $this->stack[] = $this->data; foreach ($element as $k => $v) { $this->data[$k] = $v; } } function unwrap() { $this->data = array_pop($this->stack); } function run() { ob_start (); eval (func_get_arg(0)); return ob_get_clean(); } function process($template, $data) { $this->data = $data; $this->stack = array(); $template = str_replace('<', '<?php echo \'<\'; ?>', $template); $template = preg_replace('~\{(\w+)\}~', '<?php $this->showVariable(\'$1\'); ?>', $template); $template = preg_replace('~\{LOOP:(\w+)\}~', '<?php foreach ($this->data[\'$1\'] as $ELEMENT): $this->wrap($ELEMENT); ?>', $template); $template = preg_replace('~\{ENDLOOP:(\w+)\}~', '<?php $this->unwrap(); endforeach; ?>', $template); $template = '?>' . $template; return $this->run($template); } }
В функции wrap()
и unwrap()
я использую стек, чтобы отслеживать текущее состояние переменных. Точно, wrap($ELEMENT)
сохраняет текущие данные в стек, а затем добавляет переменные внутри $ELEMENT
в текущие данные, а unwrap()
восстанавливает данные из стека назад.
Для дополнительной безопасности я добавил этот дополнительный бит, чтобы заменить <
на PHP echos:
$template = str_replace('<', '<?php echo \'<\'; ?>', $template);
В основном, чтобы предотвратить любые инъекции PHP-кода напрямую, либо <?
, <%
, или <script language="php">
.
Использование выглядит примерно так:
$engine = new TemplateEngine(); echo $engine->process($template, $data);
Это не лучший метод, но это один из способов, которым это можно было бы сделать.
Хорошо, сначала позвольте мне объяснить, что-то скажет вам, что PHP – ШАБЛОН .
Выполнение того, что вы делаете, как создание парсера шаблонов из парсера шаблонов, бессмысленно и, откровенно говоря, повторяет мне, что парсер шаблонов, такой как smarty, стал так хорошо в бесцельной задаче.
То, что вы должны делать, это создание вспомогательного элемента шаблона, а не синтаксического анализатора, поскольку он является избыточным, в терминах программирования файл шаблона называется представлением, и одной из причин, по которым им было присвоено определенное имя, является то, что люди будут знать его отдельно от моделей , Логика домена и т. Д.
То, что вы должны делать, – это найти способ инкапсулировать все ваши данные просмотра в свои представления.
Примером этого является использование 2 классов
Функциональность класса шаблона заключается в том, что Domain Logic устанавливает данные в представление и обрабатывает его.
Вот краткий пример:
class Template { private $_tpl_data = array(); public function __set($key,$data) { $this->_tpl_data[$key] = $data; } public function display($template,$display = true) { $Scope = new TemplateScope($template,$this->_tpl_data); //Inject into the view if($display === true) { $Scope->Display(); exit; } return $Scope; } }
Это расширенный базовый материал, который вы можете расширить, oko так о Scope. Это в основном класс, в котором ваши представления компилируются внутри интерпретатора, это позволит вам получить доступ к методам в классе TemplateScope, но не за пределами класса области видимости, т. Е. имя.
class TemplateScope { private $__data = array(); private $compiled; public function __construct($template,$data) { $this->__data = $data; if(file_exists($template)) { ob_start(); require_once $template; $this->compiled = ob_get_contents(); ob_end_clean(); } } public function __get($key) { return isset($this->__data[$key]) ? $this->__data[$key] : null; } public function _Display() { if($this->compiled !== null) { return $this->compiled; } } public function bold($string) { return sprintf("<strong>%s</strong>",$string); } public function _include($file) { require_once $file; // :) } }
Это только базовая и не работает, но концепция есть, Heres пример использования:
$Template = new Template(); $Template->number = 1; $Template->strings = "Hello World"; $Template->arrays = array(1,2,3,4) $Template->resource = mysql_query("SELECT 1"); $Template->objects = new stdClass(); $Template->objects->depth - new stdClass(); $Template->display("index.php");
и в шаблоне вы бы использовали традиционный php:
<?php $this->_include("header.php") ?> <ul> <?php foreach($this->arrays as $a): ?> <li><?php echo $this->bold($a) ?></li> <?php endforeach; ?> </ul>
Это также позволяет вам включать в шаблоны, у которых по-прежнему есть доступ к $this
ключевому слову, а затем включать себя, своего рода рекурсию (но ее нет).
Затем не прогматически не создавайте кеш, так как нечего кэшировать, вы должны использовать memcached
который хранит предварительно скомпилированный исходный код в памяти, пропускающий большую часть времени компиляции / интерпретации
Если меня не беспокоят кэширование или другие продвинутые темы, которые подтолкнут меня к установленному движку шаблонов, например smarty, я считаю, что сам PHP – отличный механизм шаблонов. Просто установите переменные в скрипте, как обычно, а затем включите файл шаблона
$name = 'Eric'; $locations = array('Germany', 'Panama', 'China'); include('templates/main.template.php');
main.tempate.php использует альтернативный синтаксис тегов php, который довольно легко использовать для пользователей не php, просто скажите им игнорировать что-либо, завернутое в тег php 🙂
<h2>Your name is <?php echo $name; ?></h2> <?php if(!empty($locations)): ?> <ol> <?php foreach($locations as $location): ?> <li><?php echo $location; ?></li> <?php endforeach; ?> </ol> <?php endif; ?> <p> ... page continues ... </p>
У меня был очень простой ответ на что-то KINDA, как это, прежде чем я начал использовать DOMXPath.
класс – это что-то вроде этого (не уверен, что он работает совсем как то, что вы хотите, но пища для размышлений, поскольку он работает очень просто
<?php class template{ private $template; function __CONSTRUCT($template) { //load a template $this->template = file_get_contents($template); } function __DESTRUCT() { //echo it on object destruction echo $this->template; } function set($element,$data) { //replace the element formatted however you like with whatever data $this->template = str_replace("[".$element."]",$data,$this->template); } } ?>
с этим классом вы просто создали бы объект с любым шаблоном, который хотите, и используйте функцию set, чтобы поместить все ваши данные.
простые циклы после создания объекта могут, вероятно, достичь вашей цели.
удачи
Smarty 🙂 …
PHP:
$smarty->assign("people",$peopleArray)
Смарт-шаблон:
{foreach $people as $person} <b>{$person.name}</b> {$person.surname}<br /> {/foreach}
Пара других дел, но это то, что по-умному будет по существу.
Используйте Smarty .