Небольшой урок о том, как написать простой шаблонизатор на php (аналогичный тому что используется в yii).
Для удобства напишем его используя ООП и будем использовать php7. Для начала создадим каркас класса View:
class View
{
private $path = __DIR__ . '/templates/';
public $data = [];
public function setData(array $data) : View
{
//
}
public function render(string $templateName) : string
{
//
}
}
Здесь $data будет содержать параметры которые будут переданы в шаблон. Единственный метод render() будет компилировать шаблон и возвращать готовый результат. Это позволит, например, рендерить страницу из множества модульных шаблонов:
echo (new View)
->setData([
'cart' =>
(new View)
->setData([...])
->render()
])
->render();
Опишем реалзацию для метода setData(). Он позволит не заменять данные а сливать уже указанные данные с теми что переданы в агрументе:
public function setData(array $data) : View
{
$this->data = array_merge($this->data, $data);
return $this;
}
А теперь напишем сам метод рендера. В php для этого есть функции ob_start(), ob_get_clean() для работы с буфером. На самом деле мы будем просто запускать выполнение интерпретатора и писать результат в буфер, а затем очищать буфер и возвращать результат.
public function render(string $templateName) : string
{
$path = $this->path . $templateName;
if (!file_exists($path)) {
throw new Exception('Template file ' . $path . ' does not exists');
}
extract($this->data);
ob_start();
include($path);
return ob_get_clean();
}
Логика работы проста: проверим существует ли файл и если он существует, то вызовем функцию extract() и скомпилируем шаблон.
На выходе у нас получается вот такой класс:
class View
{
private $path = __DIR__ . '/templates/';
public $data = [];
public function setData(array $data) : View
{
$this->data = array_merge($this->data, $data);
return $this;
}
public function render(string $templateName) : string
{
$path = $this->path . $templateName;
if (!file_exists($path)) {
throw new Exception('Template file ' . $path . ' does not exists');
}
extract($this->data);
ob_start();
include($path);
return ob_get_clean();
}
}