PHP Looping Template Engine – от царапин

Для группового проекта я пытаюсь создать механизм шаблонов для 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 классов

  • шаблон
  • TemplateScope

Функциональность класса шаблона заключается в том, что 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 .