В последнее время, на форуме много разговоров о шаблонизторах и заметно что многие люди, до сих пор, не понимают смысл и принципы их работы.
Думаю лучшим способом разобраться - будит написать шаблонизатор самому, чем мы сейчас, собственно, и займёмся.
И так, по велосипедимс .gif)
Создадим в корне хоста файлы index.php и Tpl.php - в котором мы будим описывать класс-шаблонизатор, и папку /templates - в которую будим складывать шаблоны.
Теперь открываем Tpl.php и создадим класс:
class Tpl
{
//...
}
Что бы мы в будущем могли без лишних телодвиженний получать доступ к объекту класса-шаблонизатора реализуем в нём паттерн Singleton
(впринципе, это не обязательно и если кому не нравится, то можно легко переделать).
class Tpl
{
protected static $instance;
protected $vars = array( );
protected $config = array( );
public static function instance( array $config = null )
{
return (is_null(static::$instance)
? static::$instance = new static($config)
: static::$instance
);
}
protected function __construct( array $config ) {
$this->config = $config;
}
protected function __clone() {
//...
}
protected function __wakeup() {
//...
}
}
И так, мы реализовали Singleton (защищенное статическое свойство Tpl::$instance хранит единый объект класса, доступ к которому осуществляется через статич. метод Tpl::instance(), прямая инициялизация класса (new Tpl) и его клонирование - запрещены.)
и два свойства класса: $vars - массив пременных шаблона и $config - массив с парамметрами конфигурации шаблонизатора.
Теперь откроем index.php и подключим шаблонизатор.
require './Tpl.php';
$tpl = Tpl::instance(array(
// путь к папке с шаблонами
'dir' => './templates',
// расширение файлов шаблонов
'ext' => 'php',
));
Настройки передаются массивом при первом вызове метода Tpl::instance() который уже инициализирует объект и сохраняет ссылку на него.
В дальнейшем, доступ к объкту можно получить через Tpl::instance() без передачи конфигов.
Едем дальше.
Реализуем функционал для работы с переменными шаблонов для чего воспользуемся "магией".
Возвращаемся к Tpl.php и дополним класс:
public function __set( $key, $value ) {
$this->vars[ $key ] = $value;
}
public function __get( $key ) {
return (isset($this->vars[ $key ]) ? $this->vars[ $key ] : null);
}
public function __isset( $key ) {
return isset($this->vars[ $key ]);
}
public function __unset( $key ) {
unset($this->vars[ $key ]);
}
Теперь мы можем манипулировать переменными шаблона как публичными свойствами класса.
Можем назанчать переменные:
$tpl->some_var = 'Some value';
... проверять
isset($tpl->some_var);
... получать
$tpl->some_var;
... и удалять
unset($tpl->some_var);
Едем дальше.
Реализуем метод обработки шаблонов.
public function render( $template, array $vars = null, $key = null )
{
if (is_array($vars)) {
$this->vars = $vars += $this->vars;
}
ob_start();
if (is_file($this->config['dir'] . '/' . $template . '.' . $this->config['ext'])) {
include $this->config['dir'] . '/' . $template . '.' . $this->config['ext'];
if (is_null($key)) {
return ob_get_clean();
}
$this->$key = ob_get_clean();
return $this;
}
throw new Exception("Template file '{$template}' not found.");
}
Что тут просиходит:
первым, обязательным аргументом, мы передаём имя шаблона,
второй, не обязательный аргумент - массив переменных шаблона которые мы можем передать напрямую,
и третий, не обязательный аргумент - имя переменной шаблона в которую будит "собран" результат обработки (удобство этой фичи будит продемонстрировано позже).
Теперь уже можно полноценно опробовать наш шаблонизатор.
Создадим в папке /templates файл welcome.php с таким сожержимым:
<center>Hello <?= $this->name ?>!</center>
... и перепишем index.php
require './Tpl.php';
$tpl = Tpl::instance(array(
'dir' => './templates',
'ext' => 'php',
));
$tpl->name = 'limp';
echo $tpl->render('welcome');
... запускаем скрипт что бы увидить результат.
Теперь усложним задачу.
Будим работать с двумя шаблонами используя один как макет и вкладывая в него второй.
Для этого создадим ещё один шаблон layout.php
<center><h1>Layout Template</h1></center>
<br>
<?= $this->content ?>
... и перепишем index.php
На этот раз будим передавать переменные напрямую в render(),
а так же воспользуемся третим аргументом что бы сразу передать результат обработки в переменную $this->content главного шаблона.
require './Tpl.php';
$tpl = Tpl::instance(array(
'dir' => './templates', // путь к папке с шаблонами
'ext' => 'php', // расширение файлов шаблонов
));
$tpl->render('welcome', array('name' => 'limp'), 'content');
echo $tpl->render('layout');
... запускаем скрипт что бы увидить результат.
Теперь по пробуем сделать наш шаблонизатор ещё функциональнее и удобнее.
Во время разработки интерфейса сайта у нас, так или иначе, будут появлятся многократно используемые участки кода/разметки. Это может быть форматированием текста, выводом пагинации и т.д.
Часто, все эти моменты оформляются в виде отдельных вспомогательных функций или классов, мы же пойдём другим путём и заложим в наш шаблонизатор немного расширяемости с помощью макросов.
Возвращаемся к Tpl.php.
Сначала изменим свойство $config добавив в массив ключ "macros" в котором мы будим сохранять зарегистрированные макросы.
protected $config = array(
'macros' => array( )
);
И реализуем методы для регистрации и вызова макросов.
public function macros( $name, Closure $lambda ) {
$this->config['macros'][ $name ] = $lambda;
}
public function __call( $name, $parameters )
{
if (isset($this->config['macros'][ $name ])) {
return call_user_func_array($this->config['macros'][ $name ], $parameters);
}
throw new Exception("Method 'Tpl::{$name}' does not exist.");
}
Откроем index.php и опробуем макросы в действии:
require './Tpl.php';
$tpl = Tpl::instance(array(
'dir' => './templates',
'ext' => 'php',
));
// регистрируем макрос "capitalize", который делает заглавной первую букву в переданной строке и красит её в красный цвет.
// действие, конечно, надуманное, макросы могут применяться и для более сложных задач.
$tpl->macros('capitalize', function($string) {
return '<b style="color:red">'. ucwords($string) . '</b>';
});
$tpl->render('welcome', array('name' => 'limp'), 'content');
echo $tpl->render('layout');
... применим макрос в шаблоне welcome.php
<center>Hello <?= $this->capitalize($this->name) ?>!</center>
... запускаем скрипт что бы увидить результат.
Столько много всего.. Не впечатлило меня) Как-то простой php из джона ближе)