Шаблон страницы
Пусть нам нужно завести новый раздел сайта— гостевую книгу. Выделим для нее отдельный каталог на сервере и создадим в нем файл примерно следующего содержания (листинг 30.1). Назовем его шаблоном страницы.
Листинг 30.1. Шаблон: gbook.htm
<html><head><title>Гостевая книга</title></head>
<body>
<h2>Добавьте свое сообщение:</h2>
<form action=gbook.php method=post>
Ваше имя: <input type=text name="New[name]"><br>
Комментарий:<br>
<textarea name="New[text]" wrap=virtual cols=60 rows=5></textarea><br>
<input type=submit name="doAdd" value="Добавить!">
</form>
<h2>Гостевая книга:</h2>
<?foreach($Book as $id=>$Entry) {?>
Имя человека: <?=$Entry['name']?><br>
Его комментарий:<br> <?=$Entry['text']?><hr>
<?}?>
</body></html>
Видите, здесь почти нет PHP-кода, за исключением разве что одного-единственного цикла foreach. Для человека, занимающегося внешним видом вашей гостевой книги и совершенно не разбирающегося в программировании, это не должно выглядеть, как непреодолимое препятствие.
В некоторых других языках программирования мы могли бы написать систему, лишенную и указанного недостатка, но обладающую всеми качествами рассматриваемой. Честно говоря, существует всего лишь один способ добиться этого: "замаскировать" инструкцию foreach специальным псевдотэгом (который, как это ни удивительно, гораздо лучше воспринимается дизайнерами), чтобы код выглядел примерно так:
<foreach src=Book>
Имя человека: $name<br>
Его комментарий:<br>$text<hr>
</foreach>
Согласен, для программиста такая замена действительно кажется смешной. Однако она сильно приближает шаблон нашей страницы к идеалу — практически "чистому" HTML-коду.
Хочу сразу сказать всем любителям разбивать один шаблон на множество файлов: их способ чаще всего не оправдывает себя при написании крупных сценариев. Дело в том, что при такой организации довольно тяжело переставлять подшаблоны внутри страницы. Кроме того, подшаблоны нужно как-то загружать, а поручать эту задачу коду страницы не очень удобно все из тех же соображений: придется работать и программисту, и верстальщику. Легче всего это представить на примере все той же гостевой книги: если бы мы выделили тело цикла foreach в отдельный файл и попытались избавиться от этой инструкции, то пришлось бы переложить задачу циклического вывода данных на плечи программиста, сообщив ему попутно имя подшаблона. Чувствуете, сколько лишних зависимостей?..
Надо заметить, что реализовать "прозрачную" замену подобных тэгов на соответствующие инструкции в PHP практически невозможно (во всяком случае, без ущерба простоте отладки сценария). Это связано с чрезвычайной слабостью этого интерпретатора в вопросе, касающемся "перехвата" и обработки ошибок во время выполнения кода. К счастью, такая слабость оказывается непреодолимой лишь в подобных "экзотических" случаях. При написании шаблонизатора она сказывается гораздо меньше.
Теперь шаблон сам вызывает генератор, который предоставляет ему нужные данные, а заодно и реагирует на запросы пользователя. Он выполняет это, например, при помощи все той же инструкции include:
Листинг 30.3. Шаблон: gbook.html
<?include "gbook.php"?>
<html><head><title>Гостевая книга</title></head>
<body>
<h2>Добавьте свое сообщение:</h2>
<form action=gbook.html method=post>
Ваше имя: <input type=text name="New[name]"><br>
. . .
Я не буду приводить текст страницы целиком, т. к. после определения формы он идентичен листингу 30.1. Итак, мы помещаем инструкцию include самой первой строчкой шаблона, и на это есть своя причина. Дело в том, что при различных, скажем так, "аварийных" событиях генератор данных может перенаправить браузер на другой адрес, не вернув управление в шаблон. Конечно, если бы include размещалась где-нибудь в середине шаблона, мы не смогли бы этого сделать, поскольку часть страницы могла быть уже отослана пользователю.
К слову сказать, при использовании шаблонизатора, описанного ближе к концу этой главы, мы преодолеваем и этот недостаток. А именно, имеется возможность вставлять вызов генератора данных в любое удобное место шаблона.
Заметьте, что шаблон имеет расширение HTML и выглядит для пользователя как обычная HTML-страница. Пользователь может и не подозревать, что в действительности сценарий написан на PHP. Но, чтобы описанный механизм заработал, нам необходимо связать расширение HTML с обработчиком PHP. Мы уже делали это в главе 29. Вот какую строчку нужно добавить в файл .htaccess, расположенный в каталоге (или "надкаталоге") сценария:
AddHandler application/x-httpd-php .html
Мы должны использовать директиву AddHandler, а не AddType, на случай, если для расширения HTML был ранее установлен другой обработчик. Им может быть, например, SSI (Server-Side Includes — Включения на стороне сервера) или даже PHP версии 3. В этом случае директива AddType "не срабатывает".
Пока применение include является для нас единственным средством обращения к генератору данных. Я все время повторяю эту фразу — "обращение к генератору данных". Вообще говоря, она не совсем верна. В действительности обращение из шаблона происходит лишь к интерфейсу сценария, но не к его ядру. Ядро доступно для шаблона лишь посредством общения с интерфейсом, и никак не иначе. В свою очередь, ядро также не может "разговаривать" с шаблоном (во всяком случае, не должно).
Мы видим, что во всех операциях передачи данных неизменно используется "посредник" — интерфейсная часть программы. Это открывает для нас интересные потенциальные возможности (которые на практике задействуются довольно редко). А именно, ядро и шаблон могут в принципе
"разговаривать на разных языках", тогда интерфейс будет служить их "переводчиком". Если задуматься, то это и есть главная задача интерфейса.