<?include'h.php';?>
<html><head>
		<title>Учебник PHP, Глава 12</title>
		</head>
		
      <DIV class=infotxt>
      <LI><A href="#a">Глава 12. Шаблоны </A>
      <UL>
        <LI><A href="#b">О чем говорилось выше 
</A>
        <LI><A href="#c">Нетривиальная система 
        шаблонов </A>
        <UL>
          <LI><A href="#d">Регистрация файлов</A> 
          <LI><A href="#e">Регистрация 
          переменных</A> 
          <LI><A href="#f">Обработка файла</A> 
          <LI><A href="#g">Вывод файла</A> 
          <LI><A href="#h">Расширение класса 
          template</A> 
          <LI><A href="#i">Недостатки системы 
          шаблонов</A> 
          <LI><A href="#j">Необоснованные надежды 
          на «идеальное решение»</A> 
          <LI><A href="#k">Снижение 
          быстродействия</A> 
          <LI><A href="#l">Ориентация дизайна на 
          PHP</A> </LI></UL>
        <LI><A href="#m">Проект: адресная 
        книга</A> 
        <LI><A href="#n">Итоги</A> </LI></UL>
      <UL></UL><A name=a></A>
      <P>&nbsp;</P>
      <P>ГЛАВА 12</P>
      <P>Шаблоны</P>
      <P>Шаблоны можно рассматривать как «расширение» программного кода. Шаблоны 
      не только автоматизируют утомительный процесс кодирования, но и 
      обеспечивают структурное деление проекта в рабочих группах. Роль такого 
      деления возрастает с увеличением объемов проекта и численности групп, а 
      также с усложнением архитектуры проекта, причем не только на стадии 
      программирования, но и при последующем сопровождении программы.</P>
      <P>Сказанное стоит пояснить на конкретном примере. Допустим, у нас имеется 
      команда разработчиков, состоящая из web-дизайнеров и программистов. В 
      идеале группа web-дизайнеров трудится над созданием привлекательного и 
      удобного сайта, а группа программистов в это время работает над 
      эффективностью и широтой возможностей web-приложения. К счастью, шаблоны 
      заметно упрощают подобное структурирование процесса. Настоящая глава 
      посвящена созданию системы шаблонов, обеспечивающих подобное «разделение 
      труда».</P>
      <P><A href="http.html://doks.gorodok.net/0" name=b></A>О чем говорилось 
выше</P>
      <P>До настоящего момента я упоминал о двух разных подходах к созданию 
      шаблонов РНР:</P>
      <UL>
        <LI>внедрение HTML в код РНР; 
        <LI>включение файлов в страницу. </LI></UL>
      <P>Хотя первая схема более понятна и проще реализуется, она также в 
      большей степени ограничивает вашу свободу действий. Главная проблема 
      заключается в том, что код РНР смешивается с компонентами HTML, 
      образующими макет страницы. Возникающие при этом проблемы связаны не 
      только с необходимостью потенциальной поддержки одновременного доступа к 
      странице и ее модификации, но и с повышенной вероятностью ошибок при 
      непосредственном просмотре и редактировании страниц.</P>
      <P>Вторая схема во многих ситуациях оказывается гораздо удобнее первой. 
      Тем не менее, хотя структура «заголовок — основная часть — колонтитул» 
      (см. главу 9)</P>
      <P>хорошо подходит для структурирования относительно малых сайтов с четко 
      определенным форматом, с увеличением объемов и сложности проекта эти 
      ограничения проявляются все заметнее. Попытки решения этих проблем привели 
      к разработке новой схемы применения шаблонов, более сложной по сравнению с 
      двумя первыми, но и обладающей существенно большей гибкостью. В этой схеме 
      разделяются два главных компонента web-приложения: дизайн и 
      программирование. Подобное деление обеспечивает возможность параллельной 
      разработки (web-дизайн и программирование) без необходимости постоянной 
      координации на протяжении всего рабочего цикла. Более того, оно позволяет 
      в будущем модифицировать один компонент, не влияя на работу другого. В 
      следующем разделе я покажу, как устроена одна из таких схем «нетривиальных 
      шаблонов». Следует помнить, что эта схема существует не только в РНР. 
      Более того, она появилась задолго до РНР и в настоящее время используется 
      в нескольких языках, включая РНР, Perl и Java Server Pages. To, что 
      описано в этой главе, — не более чем адаптация этой схемы применительно к 
      РНР.</P>
      <P><A name=c></A>Нетривиальная система шаблонов</P>
      <P>Как говорилось ранее, главной целью при разработке подобных систем 
      шаблонов является фактическое отделение дизайна от функциональных 
      возможностей. Собственно, эта система и создается для того, чтобы 
      программисты и дизайнеры могли независимо трудиться над своими аспектами 
      приложения, не мешая работе другой группы.</P>
      <P>К счастью, сделать это проще, чем кажется на первый взгляд, — при 
      условии, что до начала разработки было проведено некоторое предварительное 
      планирование. В листинге 12.1 представлен некий базовый шаблон, созданный 
      на основе материала этой главы.</P>
      <P>Листинг 12.1. Пример шаблона</P>
      <P>&lt;html&gt;</P>
      <P>&lt;head&gt;</P>
      <P>&lt;title&gt;:::::{page_title}:::::&lt;/title&gt;</P>
      <P>&lt;/head&gt;</P>
      <P>&lt;body bgcolor="{bg_color}"&gt;</P>
      <P>Welcome to your default home page. {user_name}!&lt;br&gt;</P>
      <P>You have 5 MB and 3 email addresses at your disposal.&lt;br&gt;</P>
      <P>Have fun!</P>
      <P>&lt;/body&gt;</P>
      <P>&lt;/html&gt;</P>
      <P>Обратите внимание на три строки (page_title, bg_color и userjiame), 
      заключенные в фигурные скобки ({ }). Фигурные скобки имеют особый смысл 
      при обработке шаблонов — заключенная в них строка интерпретируется как имя 
      переменной, вместо которого подставляется ее значение. Дизайнер строит 
      страницу по своему усмотрению; все, что от него потребуется, — включать в 
      соответствующие места документа эти ключевые строки. Конечно, программисты 
      и дизайнеры должны заранее согласовать имена всех переменных!</P>
      <P>Итак, как же работает эта схема? Прежде всего, возможно, нам придется 
      одновременно работать с несколькими шаблонами, обладающими одними и теми 
      же общими атрибутами. В таких ситуациях применение технологии 
      объектно-ориентированного программирования (ООП) оказывается особенно 
      эффективным. По этой причине все функции построения и выполнения операций 
      с шаблонами будут оформлены в виде методов класса. Определение класса 
      начинается так:</P>
      <P>class template {</P>
      <P>VAR $files = array( );</P>
      <P>VAR $variables = array( );</P>
      <P>VAR $openi ng_escape = '{';</P>
      <P>VAR $closing_escape = '}';</P>
      <P>В массиве $files хранятся идентификаторы файлов и содержимое каждого 
      файла. Атрибут $variables представляет собой двухмерный массив для 
      хранения файлового идентификатора (ключа) и всех соответствующих 
      переменных, обрабатываемых в схеме шаблонов. Наконец, атрибуты 
      $opening_escape и $closing_escape задают ограничители для частей шаблона, 
      которые должны заменяться системой. Как было показано в листинге 12.1, в 
      наших примерах в качестве ограничителей будут использоваться фигурные 
      скобки ({ }). Впрочем, вы можете изменить два последних атрибута и выбрать 
      ограничители по своему усмотрению. Главное — проследите за тем, чтобы эти 
      символы не использовались для других целей.</P>
      <P>Каждый метод класса решает конкретную задачу, соответствующую той или 
      иной операции в процессе обработки шаблона. На простейшем уровне этот 
      процесс можно разделить на четыре стадии.</P>
      <UL>
        <LI>Регистрация файлов — регистрация всех файлов, обрабатываемых 
        сценариями шаблонов. 
        <LI>Регистрация переменных — регистрация всех переменных, которые должны 
        заменяться своими значениями в зарегистрированных файлах. 
        <LI>Обработка файлов — замена всех переменных, находящихся между 
        ограничителями, в зарегистрированных файлах. 
        <LI>Вывод файла — вывод обработанных зарегистрированных файлов в 
        браузере. </LI></UL>
      <P>Применение концепций ООП в РНР рассматривалось в главе 6. Если вы не 
      знакомы с ООП, я рекомендую бегло просмотреть главу 6 перед тем, как 
      читать дальше.</P>
      <P><A name=d></A>Регистрация файлов</P>
      <P>В процессе регистрации содержимое файла сохраняется в массиве с ключом, 
      однозначно идентифицирующим этот файл. Метод register_file( ) открывает и 
      читает содержимое файла, имя которого передается в качестве параметра. Код 
      этого метода приведен в листинге 12.2.</P>
      <P>Листинг 12.2. Метод регистрации файла</P>
      <P>function register_file($file_id, $file_name) {</P>
      <P>// Открыть $file_name для чтения или завершить программу</P>
      <P>// с выдачей сообщения об ошибке.</P>
      <P>$fh = fopen($file_name, "r") or die("Couldn't open $file_name!");</P>
      <P>// Прочитать все содержимое файла $file_name в переменную.</P>
      <P>$file_contents = fread($fh, filesize($file_name));</P>
      <P>// Присвоить содержимое элементу массива</P>
      <P>// с ключом $file_id. $this-&gt;files[$file_id] = $file_contents;</P>
      <P>// Работа с файлом завершена, закрыть его.</P>
      <P>fclose($fh);</P>
      <P>}</P>
      <P>Параметр $file_id содержит идентификатор — «псевдоним» для последующих 
      операций с файлом, упрощающий последующие вызовы метода. Идентификатор 
      используется в качестве ключа для индексирования массива $files. Пример 
      регистрации файла:</P>
      <P>// Включить класс шаблона</P>
      <P>include("tempiate.class"):</P>
      <P>// Создать новый экземпляр класса</P>
      <P>$template = new template:</P>
      <P>// Зарегистрировать файл "homepage.html",</P>
      <P>// присвоив ему псевдоним "home"</P>
      <P>$template-&gt;register_file("home", "homepage.html");</P>
      <P><A name=e></A>Регистрация переменных</P>
      <P>После регистрации файлов необходимо зарегистрировать все переменные, 
      которые будут интерпретироваться особым образом. Метод register_variables( 
      ) (листинг 12.3) работает по тому же принципу, что и register_file( ), — 
      он читает имена переменных и сохраняет их в массиве $variables.</P>
      <P>Листинг 12.3. Метод регистрации переменнных</P>
      <P>function register_vanables($file_id, $variable_name) {</P>
      <P>// Попытаться создать массив,</P>
      <P>// содержащий переданные имена переменных</P>
      <P>$input_variables - explode(".", $variable_name);</P>
      <P>// Перебрать имена переменных</P>
      <P>while (Iist($value) = each($input_variables)) :</P>
      <P>// Присвоить значение очередному элементу массива</P>
      <P>$this-&gt;variables $this-&gt;variables[$file_id][] = $value:</P>
      <P>endwhile;</P>
      <P>}</P>
      <P>В параметре $file_id передается ранее присвоенный псевдоним файла. 
      Например, в предыдущем примере файлу homepage.html был присвоен псевдоним 
      home. Обратите внимание — при регистрации имен переменных, которые должны 
      особым образом обрабатываться в файле homepage.html, вы должны ссылаться 
      на файл по псевдониму! В параметре $variable_name передаются имена одной 
      или нескольких переменных, регистрируемых для указанного псевдонима. 
      Пример:</P>
      <P>// Включить класс шаблона include("tempiate.class");</P>
      <P>// Создать новый экземпляр класса $template = new template;</P>
      <P>// Зарегистрировать файл "homepage.html",</P>
      <P>// присвоив ему псевдоним "home" $template-&gt;register_file("home", 
      "homepage.html");</P>
      <P>// Зарегистрировать несколько переменных</P>
      <P>$template-&gt;register_variablest"home", 
      "page_title.bg_color,user_name");</P>
      <P><A name=f></A>Обработка файла</P>
      <P>После того как файлы и переменные будут зарегистрированы в системе 
      шаблонов, можно переходить к обработке зарегистрированных файлов и замене 
      всех ссылок на переменные с соответствующими значениями. Метод 
      file_parser( ) приведен в листинге 12.4.</P>
      <P>Листинг 12.4. Метод обработки файла</P>
      <P>function file_parser($file_id) {</P>
      <P>// Сколько переменных зарегистрировано для данного файла?</P>
      <P>$varcount = count($this-&gt;variables[$file_id]);</P>
      <P>// Сколько файлов зарегистрировано?</P>
      <P>$keys = array_keys($this-&gt;files):</P>
      <P>// Если файл $file_id существует в массиве</P>
      <P>$this-&gt;files</P>
      <P>// и с ним связаны зарегистрированные переменные</P>
      <P>If ( (in_array($file_id. $keys)) &amp;&amp; ($varcount &gt; 0) ) :</P>
      <P>// Сбросить $x $x = 0:</P>
      <P>// Пока остаются переменные для обработки...</P>
      <P>while ($x &lt; sizeof($this-&gt;variables[$file_id])) :</P>
      <P>// Получить имя очередной переменной $string = 
      $this-&gt;variables[$file_id][$x];</P>
      <P>// Получить значение переменной. Обратите внимание:</P>
      <P>// для получения значения используется конструкция $$.</P>
      <P>// Полученное значение подставляется в файл вместо</P>
      <P>// указанного имени переменной.GLOBAL $$string:</P>
      <P>// Построить точный текст замены вместе с ограничителями</P>
      <P>$needle = 
$this-&gt;opening_escape.$string.$this-&gt;closing_escape;</P>
      <P>// Выполнить замену.</P>
      <P>$this-&gt;files[$file_id] = str_replace( $needle.</P>
      <P>$$string.</P>
      <P>$this-&gt;files[$file_id]);</P>
      <P>// Увеличить $х $x++;</P>
      <P>endwhile;</P>
      <P>endif;</P>
      <P>}</P>
      <P>Сначала мы проверяем, присутствует ли указанное имя файла в массиве 
      $this-&gt;files. Если файл был зарегистрирован, мы также проверяем, были 
      ли для него зарегистрированы переменные, и если были — значения этих 
      переменных подставляются в содержимое $file_id. Пример:</P>
      <P>// Включить класс шаблона include("template. class") ;</P>
      <P>$page_title = "Welcome to your homepage!";</P>
      <P>$bg_color = "white"; $user_name = "Chef Jacques";</P>
      <P>// Создать новый экземпляр класса</P>
      <P>$template = new template;</P>
      <P>// Зарегистрировать файл "homepage.html",</P>
      <P>II присвоив ему псевдоним "home"</P>
      <P>$template-&gt;register_file( "home", "homepage.html");</P>
      <P>// Зарегистрировать несолько переменных</P>
      <P>$template-&gt;register_variables("home", "page_titie, bg_color, 
      user_name");</P>
      <P>$template-&gt;file_parser("home");</P>
      <P>Поскольку переменные page_title, bg_color и user_name были 
      зарегистрированы, значения каждой переменной (присвоенные в начале 
      сценария) подставляются в страницу homepage.html, хранящуюся в массиве 
      files (атрибуте объекта-шаблона). На этом предварительная подготовка 
      завершается, остается лишь вывести полученный шаблон в браузере. Эта 
      операция рассматривается в следующем разделе.</P>
      <P><A name=g></A>Вывод файла</P>
      <P>Вероятно, после обработки файла вы захотите отправить его в браузер, 
      чтобы пользователь увидел результат обработки шаблона. В нашем примере для 
      вывода</P>
      <P>файла создается отдельный метод, приведенный в листинге 12.5, однако в 
      зависимости от ситуации вывод также может интегрироваться с методом f i I 
      e_parser().</P>
      <P>Листинг 12.5. Метод вывода файла в браузере</P>
      <P>function pnnt_file($file_id) {</P>
      <P>// Вывести содержимое файла с идентификатором</P>
      <P>$file_id print $this-&gt;files[$file id];</P>
      <P>}</P>
      <P>Все очень просто — при вызове print_file( ) содержимое файла, 
      представленного ключом $file_id, передается в браузер.</P>
      <P>В листинге 12.6 приведен пример использования класса template.</P>
      <P>Листинг 12.6. Пример использования класса template</P>
      <P>// Включить класс шаблона, include("tempiate.class");</P>
      <P>// Присвоить значения переменным</P>
      <P>$page_title = "Welcome to your homepage!";</P>
      <P>$bg_color = "white"; $user_name = "Chef Jacques":</P>
      <P>// Создать новый экземпляр класса $template= new template;</P>
      <P>// Зарегистрировать файл "homepage.html" с псевдонимом "home"</P>
      <P>$template-&gt;register_file("home", "homepage.html");</P>
      <P>// Зарегистрировать переменные</P>
      <P>$template-&gt;register_variables("home", "page_title, 
      bg_color.user_name");</P>
      <P>$template-&gt;file_parser("home");</P>
      <P>// Передать результат в браузер</P>
      <P>$template-&gt;print_file("home");</P>
      <P>Если бы шаблон, приведенный в листинге 12.1, хранился в файле 
      homepage.html в одном каталоге со сценарием из листинга 12.6, то в браузер 
      был бы направлен следующий код HTML:</P>
      <P>&lt;html&gt;</P>
      <P>&lt;head&gt;</P>
      <P>&lt;title&gt;:::::Welcome to your homepage!:::::&lt;/title&gt;</P>
      <P>&lt;/head&gt;</P>
      <P>&lt;body bgcolor=white&gt;</P>
      <P>Welcome to your default home page, Chef Jacques!&lt;br&gt;</P>
      <P>You have 5 MB and 3 email addresses at your disposal.&lt;br&gt;</P>
      <P>Have fun!</P>
      <P>&lt;/body&gt;</P>
      <P>&lt;/html&gt;</P>
      <P>Как видно из приведенного примера, все зарегистрированные переменные 
      были заменены соответствующими значениями. При всей своей простоте класс 
      tempi ate</P>
      <P>обеспечивает стопроцентное разделение уровней программирования и 
      дизайна. Полный код класса template приведен в листинге 12.7.</P>
      <P>Листинг 12.7. Полный код класса template</P>
      <P>class template {</P>
      <P>VAR $files = array( );</P>
      <P>VAR $variables = array( );</P>
      <P>VAR $opening_escape = '{';</P>
      <P>VAR $closing_escape = '}' ;</P>
      <P>// Функция: register_file( )</P>
      <P>// Назначение: сохранение в массиве содержимого файла.</P>
      <P>// определяемого идентификатором $file_id</P>
      <P>function register_file($file_id. $file_name) {</P>
      <P>// Открыть $file_name для чтения или завершить программу</P>
      <P>// с выдачей сообщения об ошибке.</P>
      <P>$fh = fopen($file_name, "r") or die("Couldn't open $file_name!");</P>
      <P>// Прочитать все содержимое файла $file_name в переменную.</P>
      <P>$file_contents = fread($fh, filesize($file_name));</P>
      <P>// Присвоить содержимое элементу массива</P>
      <P>// с ключом $file_id. $this-&gt;files[$file_id] = $file_contents;</P>
      <P>// Работа с файлом завершена, закрыть его.</P>
      <P>fclose($fh):</P>
      <P>} // Функция: register_variables( )</P>
      <P>// Назначение: сохранение переменных, переданных</P>
      <P>// в параметре $variable_name. в массиве с ключом $file_id.</P>
      <P>function register_variables($file_id, $variable_name) {</P>
      <P>// Попытаться создать массив.</P>
      <P>// содержащий переданные имена переменных</P>
      <P>$input_variables = explode(".", $vahable_name);</P>
      <P>// Перебрать имена переменных</P>
      <P>while (list(, $value) = each($input_variables)) :</P>
      <P>// Присвоить значение очередному элементу массива $this-&gt;variables 
      $this-&gt;variables[$file_id][] = $value:</P>
      <P>endwhile;</P>
      <P>} // Функция: file_parser( )</P>
      <P>// Назначение: замена всех зарегистрированных переменных</P>
      <P>// в файле с идентификатором $file_id</P>
      <P>function file_parser($file_id) {</P>
      <P>// Сколько переменных зарегистрировано для данного файла?</P>
      <P>$varcount = count($this-&gt;variables[$file_id]):</P>
      <P>// Сколько файлов зарегистрировано?</P>
      <P>$keys = array_keys($this-&gt;files):</P>
      <P>// Если файл $file_id существует в массиве $this-&gt;files</P>
      <P>// и с ним связаны зарегистрированные переменные</P>
      <P>if ( (in_array($file_id. $keys)) &amp;&amp; ($varcount &gt; 0) ) :</P>
      <P>// Сбросить $х $x - 0;</P>
      <P>// Пока остаются переменные для обработки...</P>
      <P>while ($x &lt; sizeof($this-&gt;variables[$file_id])) :</P>
      <P>// Получить имя очередной переменной</P>
      <P>$string = $this-&gt;variables[$file_id][$x];</P>
      <P>// Получить значение переменной. Обратите внимание:</P>
      <P>// для получения значения используется конструкция $$.</P>
      <P>// Полученное значение подставляется в файл вместо</P>
      <P>// указанного имени переменной.</P>
      <P>GLOBAL $$string;</P>
      <P>// Построить точный текст замены вместе с ограничителями</P>
      <P>$needle = $this-&gt;opemng_escape.$string.$this-&gt;closing_escape;</P>
      <P>// Выполнить замену.</P>
      <P>$this-&gt;files[$file_id] = str_replace( $needle, $$string,</P>
      <P>$this-&gt;files[$file_idj);</P>
      <P>// Увеличить $х $x++;</P>
      <P>endwhile;</P>
      <P>endif;</P>
      <P>}</P>
      <P>// Функция: print_file()</P>
      <P>// Назначение: вывод содержимого файла,</P>
      <P>// определяемого параметром $file_id</P>
      <P>function print_file($file_id) {</P>
      <P>// Вывести содержимое файла с идентификатором $file_id</P>
      <P>print $this-&gt;files[$file_id];</P>
      <P>}</P>
      <P>} //END template.class</P>
      <P><A href="http.html://doks.gorodok.net/996" name=h></A>Расширения класса 
      template</P>
      <P>Конечно, класс tempi ate обладает весьма ограниченными возможностями, 
      хотя для проектов, создаваемых на скорую руку, он вполне подходит. 
      Объектно-ориентированные схемы хороши тем, что они позволяют легко 
      наращивать функциональность, не беспокоясь о возможных нарушениях работы 
      существующего кода. Допустим, вы решили создать новый метод, который будет 
      загружать значения для последующей замены из базы данных. Хотя такой метод 
      устроен чуть сложнее, чем метод file_parser( ), производящий простую 
      замену глобальных переменных, его реализация на базе SQL состоит из 
      нескольких строк и легко инкапсулируется в отдельном методе. Более того, 
      мы создадим нечто подобное в проекте адресной книги, завершающем эту 
      главу.</P>
      <P>В класс tempi ate можно внести несколько очевидных усовершенствований. 
      Первое — объединение функций register_file( ) и register_variables( ), 
      обеспечивающее автоматическую регистрацию переменных для каждого 
      регистрируемого файла. Конечно, при этом также необходимо реализовать 
      проверку ошибок, чтобы предотвратить регистрацию неверных файлов и 
      переменных.</P>
      <P>Однако на этом возможности усовершенствования далеко не исчерпаны. 
      Подумайте, как бы вы реализовали методы, работающие с целыми массивами? На 
      самом деле это проще, чем кажется на первый взгляд. Проанализируйте 
      решение, использованное в проекте адресной книги в конце главы. Общие 
      принципы легко трансформируются под любую конкретную реализацию.</P>
      <P>Общие схемы работы с шаблонами были реализованы на нескольких языках и 
      ни в коем случае не являются чем-то принципиально новым. В Web можно найти 
      немало информации о реализации шаблонов. Рекомендую два особенно 
      интересных ресурса — сборники статей, написанных с ориентацией на 
      JavaScript:</P>
      <UL>
        <LI><A 
        href="http.html://www.netscape.com/viewsource/long_ssjs/long_ssjs.html">http://www.netscape.com/viewsource/long_ssjs/long_ssjs.html</A>; 

        <LI><A 
        href="http.html://www.netscape.com/viewsource/schroder_template/schroder_template.html">http://www.netscape.com/viewsource/schroder_template/schroder_template.html</A>. 
        </LI></UL>
      <P>В следующей статье затронута тема использования шаблонов применительно 
      к Java Server Pages:</P>
      <UL>
        <LI><A 
        href="http.html://www-4.ibm.com/software/webservers/appserv/doc/guide/asgdwp.html">http://www-4.ibm.com/software/webservers/appserv/doc/guide/asgdwp.html</A>. 
        </LI></UL>
      <P>Кроме того, описанная схема построения шаблонов используется в 
      нескольких библиотеках РНР, среди которых наибольший интерес представляют 
      следующие:</P>
      <UL>
        <LI>PHPLib Base Library: <A 
        href="http.html://phplib.netuse.de/">http://phplib.netuse.de/</A>; 
        <LI>Richard Hayes's Template Class: <A 
        href="http.html://www.heyes-computing.net/">http://www.heyes-computing.net/</A>; 

        <LI>Fast Template: <A 
        href="http.html://www.thewebmasters.net/php">http://www.thewebmasters.net/php</A>. 
        </LI></UL>
      <P>На сайте ресурсов РНР, PHPBuilder (<A 
      href="http.html://www.phpbuilder.com/">http://www.phpbuilder.com/</A>), также 
      имеется несколько интересных учебников, посвященных обработке шаблонов. 
      Кроме того, загляните на сайт РНР Classes Repository (<A 
      href="http.html://phpclasses.upperdesign.com/">http://phpclasses.upperdesign.com/</A>), 
      здесь также можно найти несколько реализаций.</P>
      <P><A name=i></A>Недостатки системы шаблонов</P>
      <P>Хотя рассмотренная система шаблонов справляется со своей главной 
      задачей — полным разделением дизайна и программирования, она не лишена 
      недостатков. Некоторые из этих недостатков перечислены ниже.</P>
      <P><A name=j></A>Необоснованные надежды на «идеальное решение»</P>
      <P>Шаблоны помогают четко выделить в проекте аспекты программирования и 
      дизайна, но они не заменяют нормального взаимодействия между этими 
      аспектами. Более того, правильность их работы зависит от предварительного 
      согласования списка переменных, заменяемых в процессе обработки шаблона. 
      Как и в любом успешном проекте, переходить к написанию кода РНР следует 
      лишь после тщательной проработки спецификации всего приложения. Это 
      значительно уменьшает вероятность ошибок при последующей обработке, 
      приводящих к непредвиденным последствиям при использовании шаблонов.</P>
      <P><A name=k></A>Снижение быстродействия</P>
      <P>Затраты на обработку файлов приводят к некоторому замедлению работы 
      программы. В какой мере замедляется работа, зависит от ряда факторов, в 
      том числе от размера страницы, размера запроса SQL (если они задействован) 
      и аппаратной конфигурации компьютера. Как правило, эти потери настолько 
      малы, что ими можно пренебречь, но в некоторых ситуациях они оказываются 
      довольно значительными (например, при одновременной обработке нескольких 
      шаблонов в условиях высокого трафика).</P>
      <P><A name=l></A>Ориентация дизайна на РНР</P>
      <P>Одна из главных целей создания шаблонов заключается в том, чтобы по 
      возможности изолировать дизайнера от программного кода при редактировании 
      внешнего вида и поведения страницы. В идеальном случае дизайнер должен 
      обладать некоторыми навыками программирования или, по крайней мере, быть 
      знакомым с общими концепциями — переменными, циклами и условными 
      командами. Дизайнеру, абсолютно не разбирающемуся в них, применение 
      шаблонов практически ничего не даст, кроме относительно бесполезных 
      сведений из области синтаксиса. В общем, независимо от того, захотите вы 
      пользоваться этим типом шаблонов или нет, я настоятельно рекомендую 
      потратить немного времени и обучить дизайнера азам языка РНР... а еще 
      лучше — купить ему эту книгу! От этого выиграют обе стороны, поскольку 
      дизайнер приобретет дополнительные навыки и станет более ценным членом 
      рабочей группы, а у программиста появится новый источник идей. Может, 
      дизайнер и не изобретет ничего выдающегося, но зато он взглянет на 
      ситуацию под новым углом зрения, обычно недоступным для программиста.</P>
      <P><A name=m></A>Проект: адресная книга</P>
      <P>Хотя системы шаблонов хорошо подходят для многих типов web-приложений, 
      они приносят особенную пользу в приложениях, ориентированных на выборку и 
      вывод данных, в которых особенно важно обеспечить правильное 
      форматирование.</P>
      <P>Примером такого приложения является адресная книга. Представьте себе 
      обычную (бумажную) адресную книгу: все страницы выглядят практически 
      одинаково, различаются разве что буквы, с которых начинаются имена на 
      конкретной странице. Аналогичный подход можно применить и к адресной книге 
      на базе Web. Форматирование в данном случае играет еще более важную роль, 
      поскольку не исключено, что данные придется экспортировать в другое 
      приложение в каком-нибудь специфическом формате. Подобные приложения 
      прекрасно работают на базе шаблонов, поскольку дизайнеру остается лишь 
      создать единый формат страницы, который будет использоваться для всех 26 
      букв алфавита.</P>
      <P>Прежде всего, необходимо решить, какие данные и в каком формате будут 
      храниться в адресной книге. Конечно, оптимальным носителем информации в 
      данном случае является база данных, поскольку это упростит такие полезные 
      операции, как поиск и сортировка данных. В своем примере я воспользуюсь 
      СУБД MySQL. Определение таблицы выглядит следующим образом:</P>
      <P>mysql&gt;CREATE table addressbook (</P>
      <P>last_name char(35) NOT NULL,</P>
      <P>first_name char(20) MOT NULL,</P>
      <P>tel char(20) NOT NULL,</P>
      <P>email char(55) NOT NULL );</P>
      <P>Разумеется, вы можете самостоятельно добавить поля для хранения адреса, 
      города и т. д. Для наглядности я буду использовать сокращенную таблицу, 
      приведенную ранее.</P>
      <P>Теперь я возьму на себя роль дизайнера и займусь созданием шаблонов. 
      Для этого проекта нужны два шаблона. Код первого, «родительского» шаблона 
      book.html приведен в листинге 12.8.</P>
      <P>Листинг 12.8. Основной шаблон адресной книги book.html</P>
      <P>&lt;html&gt;</P>
      <P>&lt;head&gt;</P>
      <P>&lt;title&gt;:::::{page_title}:::::&lt;/title&gt;</P>
      <P>&lt;/head&gt;</P>
      <P>&lt;body bgcolor="white"&gt;</P>
      <P>&lt;table cellpadding=2 cellspacing=2 width=600&gt;</P>
      <P>&lt;h1&gt;Address Book: {letter}&lt;/h1&gt; &lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;a href="index.html.php?letter=a"&gt;A&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=b"&gt;B&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=c"&gt;C&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=d"&gt;D&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=e"&gt;E&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=f"&gt;F&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html,php?letter=g"&gt;G&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=h"&gt;H&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=i"&gt;I&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=j"&gt;J&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=k"&gt;K&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=l"&gt;L&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=m"&gt;M&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=n"&gt;N&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=o"&gt;O&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=p"&gt;P&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=q"&gt;Q&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=r"&gt;R&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=s"&gt;S&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=t"&gt;T&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=u"&gt;U&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=v"&gt;V&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=w"&gt;W&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=x"&gt;X&lt;/a&gt;&nbsp;|&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=y"&gt;Y&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=z"&gt;Z&lt;/a&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>{rows.addresses}</P>
      <P>&lt;/table&gt;</P>
      <P>&lt;/body&gt;</P>
      <P>&lt;/html&gt;</P>
      <P>Как видите, файл в основном состоит из ссылок с разными буквами 
      алфавита. Если щелкнуть на букве, в браузере отображается информация обо 
      всех контактах в адресной книге, фамилии которых начинаются с указанной 
      буквы.</P>
      <P>В странице встречаются три имени переменных, заключенных в 
      ограничители: page_title, letter и rows_addresses. Смысл первых двух 
      переменных очевиден: текст в заголовке страницы и буква адресной книги, 
      использованная для выборки текущих адресных данных. Третья переменная 
      относится к дополнительному шаблону (листинг 12.9) и определяет файл 
      конфигурации таблицы, включаемый в основной шаблон. Файлы конфигурации 
      таблиц используются в связи с тем, что в сложных страницах может быть 
      одновременно задействовано несколько шаблонов, в каждом из которых данные 
      форматируются в виде таблиц HTML. Шаблон rows.addresses (листинг 12.9) 
      выполняет вспомогательные функции и вставляется в основной шаблон 
      book.html. Вскоре вы поймете, почему это необходимо.</P>
      <P>Листинг 12.9. Вспомогательный шаблон rows.addresses</P>
      <P>&lt;tr&gt;&lt;td bgcolor="#c0c0c0"&gt;</P>
      <P>&lt;b&gt;{last_name},{first_name}&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;b&gt;{telephone}&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;b&gt;&lt;a href = 
      "mailto:{email}"&gt;{email}&lt;/a&gt;&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>В листинге 12.9 встречаются четыре переменных, заключенных в 
      ограничители: last_name, first_name, telephone и emal. Смысл этих 
      переменных очевиден (см. определение таблицы addressbook). Следует 
      заметить, что этот файл состоит только из табличных тегов строк 
      (&lt;tr&gt;...&lt;/tr&gt;) и ячеек (&lt;td&gt;...&lt;/td&gt;). Дело в том, 
      что этот файл вставляется в шаблон многократно, по одному разу для каждого 
      адреса, прочитанного из базы данных. Поскольку имя переменной 
      rows.addresses в листинге 12.8 включается внутрь тегов 
      &lt;table&gt;...&lt;/table&gt;, форматирование HTML будет обработано 
      правильно. Чтобы вы лучше поняли, как работает этот шаблон, взгляните на 
      рис. 12.1 — на нем изображена копия страницы адресной книги. Затем 
      проанализируйте листинг 12.10, содержащий исходный текст этой страницы. Вы 
      увидите, что содержимое файла rows.addresses многократно встречается в 
      странице.</P>
      <P>Листинг 12.10. Исходный текст страницы, изображенной на рис. 12.1</P>
      <P>&lt;html&gt;</P>
      <P>&lt;head&gt;</P>
      <P>&lt;title&gt;:::::Address Book:::::&lt;/title&gt;</P>
      <P>&lt;/head&gt;</P>
      <P>&lt;body bgcolor="white"&gt;</P>
      <P>&lt;table cellpadd1ng=2 cellspacing=2 width=600&gt;</P>
      <P>&lt;hl&gt;Address Book: f&lt;/hl&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;a href="index.html.php?letter=a"&gt;A&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=b"&gt;B&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=c"&gt;C&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=d"&gt;D&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=e"&gt;E&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=f"&gt;F&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=g"&gt;G&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=h"&gt;H&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=i"&gt;I&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=j"&gt;J&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=k"&gt;K&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=l"&gt;L&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=m"&gt;M&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?1etter=n"&gt;N&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=o"&gt;0&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=p"&gt;P&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=q"&gt;Q&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=r"&gt;R&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=s"&gt;S&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=t"&gt;T&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=u"&gt;U&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=v"&gt;V&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=w"&gt;W&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=x"&gt;X&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=y"&gt;Y&lt;/a&gt; |&nbsp;</P>
      <P>&lt;a href="index.html.php?letter=z"&gt;Z&lt;/a&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;t</P>
      <P>bgcolor="#c0c0c0"&gt;</P>
      <P>&lt;b&gt;Fries.Bobby&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;b&gt;(212) 563-5678&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt; "</P>
      <P>&lt;b&gt;</P>
      <P>&lt;a href="mailto.html:bobby@fries.com"&gt;bobby@fries.com&lt;/a&gt;</P>
      <P>&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td bgcolor="#c0c0c0"&gt;</P>
      <P>&lt;b&gt;Frenchy.Pierre&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;b&gt;002-(30)-09-7654321&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;tr&gt;&lt;td&gt;</P>
      <P>&lt;b&gt;&lt;a href = 
      "mailto:frenchy@frenchtv.com"&gt;<BR>frenchy@frenchtv.com&lt;/a&gt;&lt;/b&gt;</P>
      <P>&lt;/td&gt;&lt;/tr&gt;</P>
      <P>&lt;/table&gt;</P>
      <P>&lt;/body&gt;</P>
      <P>&lt;/html&gt;</P>
      <P>Как видно из приведенного листинга, в адресной книге хранятся записи 
      двух лиц, фамилии которых начинаются с буквы F: Bobby Fries и Pierre 
      Frenchy. Соответственно в таблицу вставляются данные двух записей.</P>
      <P>Дизайнерская часть проекта адресной книги завершена, и я перехожу к 
      роли программиста. Возможно, вас удивит тот факт, что класс tempiate. 
      class (см. листинг 12.7) практически не изменился, если не считать 
      появления одного нового метода — address_sql( ). Код этого метода приведен 
      в листинге 12.11.</P>
      <P>Листинг 12.11. Обработка данных, полученных в результате запроса</P>
      <P>class template {</P>
      <P>VAR $files = array( );</P>
      <P>VAR $variab!es = array( ):</P>
      <P>VAR $sql = array();</P>
      <P>VAR $opening_escape - '{';</P>
      <P>VAR $closing_escape = '}';</P>
      <P>VAR $host = "localhost";</P>
      <P>VAR $user = "root";</P>
      <P>VAR $pswd = "";</P>
      <P>VAR $db = "book";</P>
      <P>VAR $address table = "addressbook";</P>
      <P>function address_sql($file_id, $vanable_name, $letter) {</P>
      <P>// Подключиться к серверу MySQL и выбрать базу данных&nbsp;</P>
      <P>mysql_connect($this-&gt;host, $this-&gt;user, $this-&gt;pswd)</P>
      <P>or die("Couldn't connect to MySQL server!");</P>
      <P>mysql_select_db($this-&gt;db) or die('Couldn't select MySQL 
      database!");</P>
      <P>// Обратиться с запросом к базе данных</P>
      <P>$query = "SELECT last_name, first_name, tel, email</P>
      <P>FROM $this-&gt;address_table WHERE lastjiame LIKE '$letter%' ";</P>
      <P>$result = mysql_query($query);</P>
      <P>// Открыть файл "rows.addresses"</P>
      <P>// и прочитать его содержимое в переменную</P>
      <P>$fh - fopen("$variable_name", "r");</P>
      <P>$file_contents = fread($fh, filesize("rows.addresses") ):</P>
      <P>// Заменить имена переменных в ограничителях</P>
      <P>// данными из базы.</P>
      <P>while ($row = mysql_fetch_array($result)) :</P>
      <P>$new_row = $file_contents;</P>
      <P>$new_row=str_replace($this-&gt;opening_escape.<BR>"last_name".$this-&gt;closing_escape.&nbsp;</P>
      <P>$row["last_name"]. $new_row);</P>
      <P>$new_row=</P>
      <P>str_replace($th1s-&gt;opening_escape.<BR>"first_name".$this-&gt;closing_escape.</P>
      <P>$row["first_name"], $new_row);</P>
      <P>$new_row=str_replace($this-&gt;opening_escape.<BR>"telephone".$this-&gt;closing_escape.</P>
      <P>&nbsp;$row["tel"], $new_row);</P>
      <P>$new_row = 
      str_replace($this-&gt;opening_escape.<BR>"email".$this-&gt;closing_escape,</P>
      <P>&nbsp;$row["email"],</P>
      <P>$new_row);</P>
      <P>// Присоединить запись к итоговой строке замены</P>
      <P>$complete_table .= $new_row;</P>
      <P>endwhile;</P>
      <P>$sql_array_key = $variable_name;</P>
      <P>$this-&gt;sql[$sql_array_key] = $complete_table;</P>
      <P>// Включить ключ в массив variables для последующего поиска</P>
      <P>$this-&gt;variables[$file_id][ ] = $variable_name;</P>
      <P>// Закрыть файловый манипулятор fclose(lfh);</P>
      <P>Комментариев, приведенных в листинге 12.11, вполне достаточно для того, 
      чтобы вы разобрались в происходящем, однако я должен сделать несколько 
      важных замечаний. Во-первых, обратите внимание на то, что файл 
      rows.addresses открывается только один раз. Возможен и другой вариант — 
      многократно открывать и закрывать файл rows.addresses, каждый раз 
      производя замену и присоединяя его содержимое к переменной 
      $complete_table. Впрочем, такое решение будет крайне неэффективным. 
      Потратьте немного времени и разберитесь в том, как новые данные таблицы в 
      цикле присоединяются к переменной $complete_table.</P>
      <P>Второе, на что следует обратить внимание при просмотре листинга 12.11, 
      — появление пяти новых атрибутов класса: $host, $user, $pswd, $db и 
      $address_table. В этих атрибутах хранится информация, необходимая для 
      сервера SQL. Полагаю, смысл каждого атрибута понятен без объяснений, а 
      если нет — вернитесь и повторите материал главы 11.</P>
      <P>&nbsp;<IMG src="2_1_12.1Rus.jpg"></P>
      <P>Рис. 12.1. Страница адресной книги</P>
      <P>Все, что осталось сделать — написать файл index.php, инициирующий 
      обработку шаблонов, Код этого файла приведен в листинге 12.12. Если 
      щелкнуть на одной из ссылок (index.php?letter=буква) на странице book.html 
      (см. листинг 12.8), загружается страница index.php, которая, в свою 
      очередь, заново строит book.html с включением новой информации.</P>
      <P>Листинг 12.12. Обработчик шаблонов index.php</P>
      <P>include("Listing12-11.php"); $page_title = "Address Book";</P>
      <P>// По умолчанию загружается страница с фамилиями,</P>
      <P>// начинающимися с буквы 'а' if (! isset($letter) ) :</P>
      <P>$letter = "а";</P>
      <P>endif ;</P>
      <P>$tpl = new template;</P>
      <P>$tpl-&gt;register_file("book", "book.html");</P>
      <P>$tpl-&gt;register_variables("book", "page_title.letter");</P>
      <P>$tpl -&gt;address_sql("book", "rows.addresses", "$letter");</P>
      <P>$tpl -&gt;file_parser("book");</P>
      <P>$tpl-&gt;phnt_fil("book");</P>
      <P>Перед вами практический пример, показывающий, как при помощи шаблонов 
      организовать эффективное разделение труда между программистом и 
      дизайнером. Подумайте, как бы вы использовали шаблоны для организации 
      своих разработок. Готов поспорить, что вы найдете им полезное 
      применение.</P>
      <P><A name=n></A>Итоги</P>
      <P>В этой главе была представлена концепция, особенно важная как для РНР, 
      так и для web-программирования в целом, — применение шаблонов. Глава 
      началась с обзора двух схем; упоминавшихся ранее, — простой замены 
      переменных средствами РНР и логическим делением страницы при помощи 
      включаемых файлов. Затем мы познакомились с третьей схемой применения 
      шаблонов, позволяющей полностью отделить программирование от дизайна 
      страницы. Оставшаяся часть главы была посвящена анализу класса, 
      построенного для реализации шаблонов такого рода. Главу завершает пример 
      практического использования шаблонов в адресной книге на базе Web. В 
      частности, в этой главе рассматривались следующие темы:</P>
      <UL>
        <LI>для чего нужны шаблоны; 
        <LI>простой шаблон № 1: внедрение РНР в HTML; 
        <LI>простой шаблон № 2: разделение компонентов страницы при помощи 
        включаемых файлов; 
        <LI>нетривиальное использование шаблонов для полного разделения 
        программирования и дизайна; 
        <LI>класс для работы с шаблонами; 
        <LI>регистрация файлов; 
        <LI>регистрация переменных; 
        <LI>подстановка значений переменных в файл; 
        <LI>вывод файла в браузере; 
        <LI>недостатки шаблонов; 
        <LI>адресная книга, расширяющая стандартный класс шаблона за счет 
        применения запросов SQL. </LI></UL>
      <P>В следующей главе мы продолжим знакомство с разработкой динамических 
      web-приложений. Вы узнаете, как при помощи cookie и отслеживания сеансовых 
      данных наделить ваш web-сайт новыми интерактивными 
      возможностями.</P></LI></DIV>
<center>
[ <a href="11.php">Назад</a> | <a href="index.php">Содержание</a> | <a href="13.php">Вперед</a> ]
</center><br>
<? include_once '../../sys/inc/tfoot.php'; ?>