- Доброго времени суток,
- Начну с описания синтаксиса:
- 1) Переменные:
- 2) Блоки:
- 3) Проверки:
- 4) Функции:
- Теперь о принципах:
- Шаблонизатор я решил разделить на две части:
- Много подумать заставил процесс инклуда внутри шаблонов:
- Php код внутри:
- Ну и, наконец, какими принципами я руководствовался решая, какой будет синтаксис:
- Код самого шаблонизатора:
- Сравнение кода:
- Подключение:
- Скачать:
- Заключение:
- Создание собственного шаблонизатора
- Введение
- Курс «PHP-разработчик с нуля»
- Курс «SQL и получение данных»
- Курс «веб-разработчик с нуля»
- Создание шаблонов
- Создание шаблонизатора
- Вывод шаблона на экран
Доброго времени суток,
Хочу рассказать о своём шаблонизаторе для проектов на PHP.
Понимаю, что рискую быть обвинённым в изобретении велосипеда, поэтому объясню свои мотивы: Большинство шаблонизаторов меня не устраивают изначально, среди них Smarty, Quicky и все им подобные, причина — мне кажется, что шаблонизатор должен избавлять от использования логики в шаблонах, а не навязывать свой синтаксис для той же логики.
Иначе говоря, такой:
подходы для меня абсолютно неприемлимы!
Пожалуй, из всех шаблонизаторов больше всех удовлетворяет моим требованиям xtemplate, но у него есть целый ряд недостатков которые меня раздражают, например то, что все страницы нужно обрамлять в блоки, или то, что он интерпретирует шаблоны, а не компилирует, благодаря чему скоростью похвастаться не может. Ну и последнее — я решил написать шаблонизатор так, чтобы не было никаких проблем с добавлением функционала, а также, чтобы он был совместим с нативным шаблонизатором, который я использовал до этого, и к которому привык. Дело в том что конструкция
В один прекрасный момент я понял, что проще написать свой шаблонизатор, чем искать тот, который мне подойдет. И, думаю, оказался прав, ведь дело обошлось несколькими вечерами.
Вообще говоря, процесс мне показался довольно интересным, и появилось много моментов, которые хотелось бы обсудить с сообществом.
Начну с описания синтаксиса:
1) Переменные:
2) Блоки:
3) Проверки:
4) Функции:
- function up ( $text ) <
- return strtoupper ( $text )
- >
- < up >текст который нужно сделать БОЛЬШИМ < / up >
или как-то ещё. Пока склоняюсь к первому варианту, его проще реализовать!
Теперь о принципах:
Шаблонизатор я решил разделить на две части:
1) Сам шаблонизатор (максимально компактный, всё самое нужное)
2) Компилятор (а вот тут вот всё остальное)
Это необходимо для повышения производительности, ведь не имеет никакого смысла в 8 кб кода компилятора, если шаблон уже скомпилирован и с тех пор не менялся.
Много подумать заставил процесс инклуда внутри шаблонов:
На первый взгляд, момент может показаться пустяковым, но это не так. Вообще говоря, инклуды пришлось разделить на две части — статические и динамические. Статический инклуд — это обычный инклуд, например
Такой инклуд обработается следующим образом — на его места вставится код из some_page.html, время изменения у файла откомпилированного шаблона будет на 1 секунду больше чем у самого шаблона, и из этого шаблонизатор узнает что нужно подключить специальный, также созданный компилятором файл, в который будет добавлена следующая строчка:
Таким образом, при изменении этого файла — весь шаблон будет перекомпилирован.
Зачем это нужно, почему не вставить просто инклуд? А что если потребуется выводить блок из 1000 строк, внутри которого для удобства будет вставлен инклуд? Тогда такой фокус очень существенно поможет производительности!
Теперь о другом типе инклудов — динамические. Выглядит это чудо в моём шаблонизаторе например вот так:
То есть мы инклудим не какой-нибудь заранее указанный файл, а берём его имя или часть имени из переменной! Иногда может быть очень удобно, но старый способ при таком подходе уже не прокатит, ведь нужно чтобы при изменении в бизнес логике переменной, инклудился уже другой файл, поэтому такая конструкция откомпилируется в следующий код:
Замечу что на данный момент такой инклуд не будет работать внутри блока, то есть работать будет, но внутри подключённого файла переменные блока будут недоступны, но думаю это не очень страшно, ведь у меня в отличие от xtpl блоки нужны только для циклического вывода какого-нибудь массива.
Php код внутри:
Можно спокойно использовать, и хорошо подумал, но решил не запрещать php код в шаблонах.
Понимаю, вызовет много споров, но считаю что нет смысла запрещать php, так как не сталкивался с такими ситуациями, когда это имеет смысл, а не доставляет неудобства в некоторых ситуациях.
Ну и, наконец, какими принципами я руководствовался решая, какой будет синтаксис:
1) Минимум логики, всю логику — бизнес логике
2) Всё как можно естественнее
3) Меньше кода
4) Максимум возможностей
Код самого шаблонизатора:
- class tpl <
- function tpl ( $tplDir , $tmpDir ) <
- $this -> tplDir = $tplDir ;
- $this -> tmpDir = $tmpDir ;
- >
- function Render ( $Path ) <
- $tmpName = ‘tpl_’ . str_replace ( array ( ‘/’ , ‘ \\ ‘ ) , ‘.’ , $Path ) . ‘.php’ ;
- $tmpPath = $this -> tmpDir . ‘/’ . $tmpName ;
- if ( file_exists ( $tmpPath ) )
- $tmpChange = filemtime ( $tmpPath ) ;
- $tplChange = filemtime ( $Path ) ;
- if ( $tplChange + 1 == $tmpChange ) include ( $tmpPath . ‘.coll.php’ ) ;
- elseif ( $tplChange != $tmpChange ) $needCompile = true ;
- if ( $needCompile ) <
- # Вызов компилятора
- include_once ‘tcompiler.class.php’ ;
- $compiler = new tcompiler ( $this , $this -> tmpDir ) ;
- $compiler -> compile ( $this -> tplDir . ‘/’ . $Path , $tmpPath ) ;
- >
- include $tmpPath ;
- >
- >
- ?>
Работает довольно долго и лучше использовать хэш, но я протестировал, хэш работает дольше.
Сравнение кода:
Решил в удобном виде привести листинги кода в разных шаблонизаторах делающих одно и тоже, чтобы можно быро сравнить читаемость и удобство подходов
Мой
- $tpl -> num = 4815162342 ;
- $tpl -> post [ ‘page’ ] [ ‘id’ ] = 316 ;
- for ( $i = 1 ; $i < 30 ; $i ++ ) $tpl ->bin [ ] = array ( ‘dec’ => $i , ‘bin’ => decbin ( $i ) ) ;
- for ( $i = 1 ; $i < 10 ; $i ++ ) for ( $j = 1 ; $j < 10 ; $j ++ ) $tpl ->table [ $i ] [ ‘row’ ] [ $j ] [ ‘num’ ] = $i * $j ;
- $smarty -> assign ( «num» , 4815162342 ) ;
- $smarty -> assign ( «post» , array ( ‘page’ => array ( ‘id’ => 316 ) ) ) ;
- for ( $i = 1 ; $i < 30 ; $i ++ ) $bin [ ] = array ( 'dec' =>$i , ‘bin’ => decbin ( $i ) ) ;
- $smarty -> assign ( «bin» , $bin ) ;
- for ( $i = 1 ; $i < 10 ; $i ++ ) for ( $j = 1 ; $j < 10 ; $j ++ ) $table [ $i ] [ 'row' ] [ $j ] [ 'num' ] = $i * $j ;
- $smarty -> assign ( «table» , $table ) ;
- $xtpl -> assign ( ‘num’ , 4815162342 ) ;
- $post [ ‘page’ ] [ ‘id’ ] = 316 ;
- $xtpl -> assign ( ‘post’ , $post ) ;
- for ( $i = 1 ; $i < 30 ; $i ++ ) $xtpl ->insert_loop ( «page.bin» , array ( «dec» => $i , «bin» => decbin ( $i ) ) ) ;
- for ( $i = 1 ; $i < 10 ; $i ++ ) <
- for ( $j = 1 ; $j < 10 ; $j ++ ) $xtpl ->insert_loop ( «page.table.row» , ‘rownum’ , $i * $j ) ;
- $xtpl -> parse ( «page.table» ) ;
- >
Подключение:
- require_once ‘путь_до_шаблонизатоора/tpl.class.php’ ;
- $tpl = new tpl ( ‘путь_к_папке_с_шаблонами’ , ‘путь_к_папке_с_кешем’ ) ;
Не забудьте дать права папке с кешем!
Скачать:
Пока шаблонизатор лежит вот тут скачать, пока это только Бета -версия, поэтому не стоит тестить на серьёзных проектах, я лишь хотел выслушать замечания, и идеи на эту тему!
Если эксперемент удасться и подобный гибрид нативного и обычного шаблонизатора будет кому-то нужен, обязательно, буду его развивать. Кстати скорее всего он будет называться «LL».
По поводу багов просьба отписываться на olegemby.ru
Заключение:
В заключение не буду делать громких заявлений, вроде «В отдельных случаях данный шаблонизатор быстрее php native». Все мы понимаем, что в отдельных случаях трактор «Беларусь» может оказаться быстрее новенькой Porshe Panamera, в любом случае шаблонизатор будет медленнее, хотябы потому что ему нужно сравнивать даты изменения шаблона и его откомпилированной версии, а это два лишних обращения к ФС. Касатемо оптимизаций, никто не мешает оптимизировать и нативный код.
Разумеется, как и все шаблонизаторы, мой работает медленнее нативного php, но на самую малость, в доказательство привожу результаты тестов:
Все тесты проводил по несколько раз, дабы убедиться, что НЛО не повлияло на результаты. Если что выложил их сюда.
Создание собственного шаблонизатора
От автора: Разрабатывая веб-приложения, очень хорошей практикой является отделение логики скрипта от его дизайна. В таком случае очень удобно выполнять всевозможные правки по дизайну, не затрагивая логики. И наоборот, изменяя логическую часть приложения – внешний вид остается нетронутым. Но при создании приложений по такой структуре возникает вопрос, как передать переменные в дизайнерскую часть? Поэтому в данном уроке мы с Вами научимся создавать собственный несложный шаблонизатор, при помощи которого можно передавать переменные из логической части скрипта в дизайнерскую.
Введение
Первым делом определимся с понятием шаблона. Шаблоны — это отдельные файлы которые занимаются выводом данных скрипта на экран. То есть они занимаются только выводом информации, при этом шаблон только получает данные для вывода и ни как их не формирует. Из этого следует, что шаблоны содержат практически чистый HTML с минимальными вставками PHP кода, который используется для отображения данных переменных, формирования условий (if — else) и описания циклов (foreach) для обхода по массивам. Шаблоны бывают самых различных видов, а вместе с тем и шаблонизаторы. Но различают два основных вида шаблонов по способу передачи данных. Первый предусматривает передачу значений обычных переменных, которые в последствии, будут выведены на экран обычным образом, к примеру, используя функцию echo:
Курс «PHP-разработчик с нуля»
— Научитесь создавать сайты и веб-приложения на языке PHP.
— Изучите актуальные фреймворки Laravel, Simfony и Yii2.
— 78 часов теории и 361 час практики.
— Вы создадите 5 масштабных проектов для портфолио.
— Помощь с поиском работы или стажировки.
Курс «SQL и получение данных»
— Освоите один из основных инструментов работы с данными.
— 20 часов теории, 32 часа практики.
— Видеолекции, вебинары, практические задания и тренажёр.
— Выполните 6 домашних работ и итоговый проект.
— Помощь с поиском работы или стажировки.
Курс «веб-разработчик с нуля»
— Научитесь программировать на JavaScript и PHP.
— Сможете создавать сайты и веб-приложения.
— Сможете уверенно работать и с фронтендом, и с бэкендом веб-сервисов.
— Выполните 9 масштабных проектов для портфолио
— Помощь с поиском работы или стажировки.
Второй вид предусматривает вставку в шаблон специальных меток, которые будут заменены шаблонизаором на соответствующие значения. Вот пример такой метки:
В данном уроке мы будем рассматривать первый тип шаблонов. Так как этот тип наиболее удачен и функционален. Смотрите, язык PHP по своей структуре уже является очень хорошим шаблонизатором, так как очень легко встраивается в разметку HTML. Если же мы используем в шаблонах специальные метки () , то для вывода данных, нам потребуется писать специальную функцию, которая отыщет все метки и заменит их, на соответствующие данные. Но что получается, PHP и так очень хорошо встраивается в PHP, а мы пишем дополнительные функции для вывода переменных на экран. Хотя можем ограничиться обычной функцией echo:
Создание шаблонов
Для сегодняшнего урока мы будем использовать следующий сайт:
Вот код файла index.php который, выводит главную страницу на экран:
%s
Как Вы видите в этом файле логика скрипта тесно связана с его дизайном. Поэтому давайте это исправим и создадим шаблон для главной страницы тестового сайта. Вот код шаблона:
Как Вы видите в данный файл я вынес только дизайн главной страницы сайта. Для вывода данных сайта используются обычные переменные PHP. Цикл foreach описан при помощи альтернативного синтаксиса. Обратите внимание, что код данного файла достаточно прост и состоит практически из разметки HTML, что упрощает редактирование дизайна. Данный файл я сохраняю в папку templates под именем index.tpl.php.
В свою очередь файл index.php, файл который выводит главную страницу на экран, теперь содержит только логическую часть:
Теперь, когда у нас есть шаблон, необходимо передать ему данные и вывести на экран.
Создание шаблонизатора
В качестве шаблонизатора в нашем случае будет выступать функция:
Данная функция, принимает два параметра: $tmp – имя шаблона (только имя – без расширения и строки tpl), $vars = array() – необязательный параметр – массив переменных которые необходимо передать в шаблон.
В данной функции проверяем, существует ли в папке templates нужный шаблон. И если он существует — то первым делом включаем буферизированный вывод, используя функцию ob_start(). При этом весь вывод на экран будет попадать в буфер обмена. Далее нужно создать переменные, которые будут переданы в шаблон. Эти переменные мы передаем в виде массива $vars. Это обычный ассоциативный массив, ключи которого содержат имена переменных, а значения, соответственно – значения этих переменных. Используя функцию extract($vars), мы создаем в памяти переменные из массива $vars. Имена которых, соответствуют ключам данного массива.
После этого необходимо только лишь подключить нужный файл шаблона, что мы собственно и делаем. При этом на экран ничего выведено не будет, так как включен буферизированный вывод. Значит необходимо очистить буфер обмена. Для этого используем функцию ob_get_clean(), она очищает буфер обмена и возвращает его содержимое, которое мы вернем как результат работы функции в целом.
На этом шаблонизатор завешен.
Вывод шаблона на экран
Теперь давайте посмотрим как использовать данный шаблонизатор. В файле index.php, который выводит главную страницу на экран добавим следующий код: