Изучаем PHP программирование

   Search   

Русская версия | English version   

Скрипты :: Секреты профессионалов :: Link :: FAQ   Пишите письма  



 

главная :: основы PHP

Заголовок

Нетривиальная система шаблонов Как говорилось ранее, главной целью при разработке подобных систем шаблонов является фактическое отделение дизайна от функциональных возможностей. Собственно, эта система и создается для того, чтобы программисты и дизайнеры могли независимо трудиться над своими аспектами приложения, не мешая работе другой группы. К счастью, сделать это проще, чем кажется на первый взгляд, — при условии, что до начала разработки было проведено некоторое предварительное планирование. В листинге 12.1 представлен некий базовый шаблон, созданный на основе материала этой главы. Листинг 12.1. Пример шаблона :::::{page_title}::::: Welcome to your default home page. {user_name}!
You have 5 MB and 3 email addresses at your disposal.
Have fun!

Hosted by uCoz
Обратите внимание на три строки (page_title, bg_color и userjiame), заключенные в фигурные скобки ({ }). Фигурные скобки имеют особый смысл при обработке шаблонов — заключенная в них строка интерпретируется как имя переменной, вместо которого подставляется ее значение. Дизайнер строит страницу по своему усмотрению; все, что от него потребуется, — включать в соответствующие места документа эти ключевые строки. Конечно, программисты и дизайнеры должны заранее согласовать имена всех переменных! Итак, как же работает эта схема? Прежде всего, возможно, нам придется одновременно работать с несколькими шаблонами, обладающими одними и теми же общими атрибутами. В таких ситуациях применение технологии объектно-ориентированного программирования (ООП) оказывается особенно эффективным. По этой причине все функции построения и выполнения операций с шаблонами будут оформлены в виде методов класса. Определение класса начинается так: class template { VAR $files = array( ); VAR $variables = array( ); VAR $openi ng_escape = '{'; VAR $closing_escape = '}'; В массиве $files хранятся идентификаторы файлов и содержимое каждого файла. Атрибут $variables представляет собой двухмерный массив для хранения файлового идентификатора (ключа) и всех соответствующих переменных, обрабатываемых в схеме шаблонов. Наконец, атрибуты $opening_escape и $closing_escape задают ограничители для частей шаблона, которые должны заменяться системой. Как было показано в листинге 12.1, в наших примерах в качестве ограничителей будут использоваться фигурные скобки ({ }). Впрочем, вы можете изменить два последних атрибута и выбрать ограничители по своему усмотрению. Главное — проследите за тем, чтобы эти символы не использовались для других целей. Каждый метод класса решает конкретную задачу, соответствующую той или иной операции в процессе обработки шаблона. На простейшем уровне этот процесс можно разделить на четыре стадии. Регистрация файлов — регистрация всех файлов, обрабатываемых сценариями шаблонов. Регистрация переменных — регистрация всех переменных, которые должны заменяться своими значениями в зарегистрированных файлах. Обработка файлов — замена всех переменных, находящихся между ограничителями, в зарегистрированных файлах. Вывод файла — вывод обработанных зарегистрированных файлов в браузере. Применение концепций ООП в РНР рассматривалось в главе 6. Если вы не знакомы с ООП, я рекомендую бегло просмотреть главу 6 перед тем, как читать дальше. Регистрация файлов В процессе регистрации содержимое файла сохраняется в массиве с ключом, однозначно идентифицирующим этот файл. Метод register_file( ) открывает и читает содержимое файла, имя которого передается в качестве параметра. Код этого метода приведен в листинге 12.2. Листинг 12.2. Метод регистрации файла function register_file($file_id, $file_name) { // Открыть $file_name для чтения или завершить программу // с выдачей сообщения об ошибке. $fh = fopen($file_name, "r") or die("Couldn't open $file_name!"); // Прочитать все содержимое файла $file_name в переменную. $file_contents = fread($fh, filesize($file_name)); // Присвоить содержимое элементу массива // с ключом $file_id. $this->files[$file_id] = $file_contents; // Работа с файлом завершена, закрыть его. fclose($fh); } Параметр $file_id содержит идентификатор — «псевдоним» для последующих операций с файлом, упрощающий последующие вызовы метода. Идентификатор используется в качестве ключа для индексирования массива $files. Пример регистрации файла: // Включить класс шаблона include("tempiate.class"): // Создать новый экземпляр класса $template = new template: // Зарегистрировать файл "homepage.html", // присвоив ему псевдоним "home" $template->register_file("home", "homepage.html"); Регистрация переменных После регистрации файлов необходимо зарегистрировать все переменные, которые будут интерпретироваться особым образом. Метод register_variables( ) (листинг 12.3) работает по тому же принципу, что и register_file( ), — он читает имена переменных и сохраняет их в массиве $variables. Листинг 12.3. Метод регистрации переменнных function register_vanables($file_id, $variable_name) { // Попытаться создать массив, // содержащий переданные имена переменных $input_variables - explode(".", $variable_name); // Перебрать имена переменных while (Iist($value) = each($input_variables)) : // Присвоить значение очередному элементу массива $this->variables $this->variables[$file_id][] = $value: endwhile; } В параметре $file_id передается ранее присвоенный псевдоним файла. Например, в предыдущем примере файлу homepage.html был присвоен псевдоним home. Обратите внимание — при регистрации имен переменных, которые должны особым образом обрабатываться в файле homepage.html, вы должны ссылаться на файл по псевдониму! В параметре $variable_name передаются имена одной или нескольких переменных, регистрируемых для указанного псевдонима. Пример: // Включить класс шаблона include("tempiate.class"); // Создать новый экземпляр класса $template = new template; // Зарегистрировать файл "homepage.html", // присвоив ему псевдоним "home" $template->register_file("home", "homepage.html"); // Зарегистрировать несколько переменных $template->register_variablest"home", "page_title.bg_color,user_name"); Обработка файла После того как файлы и переменные будут зарегистрированы в системе шаблонов, можно переходить к обработке зарегистрированных файлов и замене всех ссылок на переменные с соответствующими значениями. Метод file_parser( ) приведен в листинге 12.4. Листинг 12.4. Метод обработки файла function file_parser($file_id) { // Сколько переменных зарегистрировано для данного файла? $varcount = count($this->variables[$file_id]); // Сколько файлов зарегистрировано? $keys = array_keys($this->files): // Если файл $file_id существует в массиве $this->files // и с ним связаны зарегистрированные переменные If ( (in_array($file_id. $keys)) && ($varcount > 0) ) : // Сбросить $x $x = 0: // Пока остаются переменные для обработки... while ($x < sizeof($this->variables[$file_id])) : // Получить имя очередной переменной $string = $this->variables[$file_id][$x]; // Получить значение переменной. Обратите внимание: // для получения значения используется конструкция $$. // Полученное значение подставляется в файл вместо // указанного имени переменной.GLOBAL $$string: // Построить точный текст замены вместе с ограничителями $needle = $this->opening_escape.$string.$this->closing_escape; // Выполнить замену. $this->files[$file_id] = str_replace( $needle. $$string. $this->files[$file_id]); // Увеличить $х $x++; endwhile; endif; } Сначала мы проверяем, присутствует ли указанное имя файла в массиве $this->files. Если файл был зарегистрирован, мы также проверяем, были ли для него зарегистрированы переменные, и если были — значения этих переменных подставляются в содержимое $file_id. Пример: // Включить класс шаблона include("template. class") ; $page_title = "Welcome to your homepage!"; $bg_color = "white"; $user_name = "Chef Jacques"; // Создать новый экземпляр класса $template = new template; // Зарегистрировать файл "homepage.html", II присвоив ему псевдоним "home" $template->register_file( "home", "homepage.html"); // Зарегистрировать несолько переменных $template->register_variables("home", "page_titie, bg_color, user_name"); $template->file_parser("home"); Поскольку переменные page_title, bg_color и user_name были зарегистрированы, значения каждой переменной (присвоенные в начале сценария) подставляются в страницу homepage.html, хранящуюся в массиве files (атрибуте объекта-шаблона). На этом предварительная подготовка завершается, остается лишь вывести полученный шаблон в браузере. Эта операция рассматривается в следующем разделе. Вывод файла Вероятно, после обработки файла вы захотите отправить его в браузер, чтобы пользователь увидел результат обработки шаблона. В нашем примере для вывода файла создается отдельный метод, приведенный в листинге 12.5, однако в зависимости от ситуации вывод также может интегрироваться с методом f i I e_parser(). Листинг 12.5. Метод вывода файла в браузере function pnnt_file($file_id) { // Вывести содержимое файла с идентификатором $file_id print $this->files[$file id]; } Все очень просто — при вызове print_file( ) содержимое файла, представленного ключом $file_id, передается в браузер. В листинге 12.6 приведен пример использования класса template. Листинг 12.6. Пример использования класса template // Включить класс шаблона, include("tempiate.class"); // Присвоить значения переменным $page_title = "Welcome to your homepage!"; $bg_color = "white"; $user_name = "Chef Jacques": // Создать новый экземпляр класса $template= new template; // Зарегистрировать файл "homepage.html" с псевдонимом "home" $template->register_file("home", "homepage.html"); // Зарегистрировать переменные $template->register_variables("home", "page_title, bg_color.user_name"); $template->file_parser("home"); // Передать результат в браузер $template->print_file("home"); Если бы шаблон, приведенный в листинге 12.1, хранился в файле homepage.html в одном каталоге со сценарием из листинга 12.6, то в браузер был бы направлен следующий код HTML: :::::Welcome to your homepage!::::: Welcome to your default home page, Chef Jacques!
You have 5 MB and 3 email addresses at your disposal.
Have fun!
Hosted by uCoz
Как видно из приведенного примера, все зарегистрированные переменные были заменены соответствующими значениями. При всей своей простоте класс tempi ate обеспечивает стопроцентное разделение уровней программирования и дизайна. Полный код класса template приведен в листинге 12.7. Листинг 12.7. Полный код класса template class template { VAR $files = array( ); VAR $variables = array( ); VAR $opening_escape = '{'; VAR $closing_escape = '}' ; // Функция: register_file( ) // Назначение: сохранение в массиве содержимого файла. // определяемого идентификатором $file_id function register_file($file_id. $file_name) { // Открыть $file_name для чтения или завершить программу // с выдачей сообщения об ошибке. $fh = fopen($file_name, "r") or die("Couldn't open $file_name!"); // Прочитать все содержимое файла $file_name в переменную. $file_contents = fread($fh, filesize($file_name)); // Присвоить содержимое элементу массива // с ключом $file_id. $this->files[$file_id] = $file_contents; // Работа с файлом завершена, закрыть его. fclose($fh): } // Функция: register_variables( ) // Назначение: сохранение переменных, переданных // в параметре $variable_name. в массиве с ключом $file_id. function register_variables($file_id, $variable_name) { // Попытаться создать массив. // содержащий переданные имена переменных $input_variables = explode(".", $vahable_name); // Перебрать имена переменных while (list(, $value) = each($input_variables)) : // Присвоить значение очередному элементу массива $this->variables $this->variables[$file_id][] = $value: endwhile; } // Функция: file_parser( ) // Назначение: замена всех зарегистрированных переменных // в файле с идентификатором $file_id function file_parser($file_id) { // Сколько переменных зарегистрировано для данного файла? $varcount = count($this->variables[$file_id]): // Сколько файлов зарегистрировано? $keys = array_keys($this->files): // Если файл $file_id существует в массиве $this->files // и с ним связаны зарегистрированные переменные if ( (in_array($file_id. $keys)) && ($varcount > 0) ) : // Сбросить $х $x - 0; // Пока остаются переменные для обработки... while ($x < sizeof($this->variables[$file_id])) : // Получить имя очередной переменной $string = $this->variables[$file_id][$x]; // Получить значение переменной. Обратите внимание: // для получения значения используется конструкция $$. // Полученное значение подставляется в файл вместо // указанного имени переменной. GLOBAL $$string; // Построить точный текст замены вместе с ограничителями $needle = $this->opemng_escape.$string.$this->closing_escape; // Выполнить замену. $this->files[$file_id] = str_replace( $needle, $$string, $this->files[$file_idj); // Увеличить $х $x++; endwhile; endif; } // Функция: print_file() // Назначение: вывод содержимого файла, // определяемого параметром $file_id function print_file($file_id) { // Вывести содержимое файла с идентификатором $file_id print $this->files[$file_id]; } } //END template.class Расширения класса template Конечно, класс tempi ate обладает весьма ограниченными возможностями, хотя для проектов, создаваемых на скорую руку, он вполне подходит. Объектно-ориентированные схемы хороши тем, что они позволяют легко наращивать функциональность, не беспокоясь о возможных нарушениях работы существующего кода. Допустим, вы решили создать новый метод, который будет загружать значения для последующей замены из базы данных. Хотя такой метод устроен чуть сложнее, чем метод file_parser( ), производящий простую замену глобальных переменных, его реализация на базе SQL состоит из нескольких строк и легко инкапсулируется в отдельном методе. Более того, мы создадим нечто подобное в проекте адресной книги, завершающем эту главу. В класс tempi ate можно внести несколько очевидных усовершенствований. Первое — объединение функций register_file( ) и register_variables( ), обеспечивающее автоматическую регистрацию переменных для каждого регистрируемого файла. Конечно, при этом также необходимо реализовать проверку ошибок, чтобы предотвратить регистрацию неверных файлов и переменных. Однако на этом возможности усовершенствования далеко не исчерпаны. Подумайте, как бы вы реализовали методы, работающие с целыми массивами? На самом деле это проще, чем кажется на первый взгляд. Проанализируйте решение, использованное в проекте адресной книги в конце главы. Общие принципы легко трансформируются под любую конкретную реализацию. Общие схемы работы с шаблонами были реализованы на нескольких языках и ни в коем случае не являются чем-то принципиально новым. В Web можно найти немало информации о реализации шаблонов. Рекомендую два особенно интересных ресурса — сборники статей, написанных с ориентацией на JavaScript: http://www.netscape.com/viewsource/long_ssjs/long_ssjs.html; http://www.netscape.com/viewsource/schroder_template/schroder_template.html. В следующей статье затронута тема использования шаблонов применительно к Java Server Pages: http://www-4.ibm.com/software/webservers/appserv/doc/guide/asgdwp.html. Кроме того, описанная схема построения шаблонов используется в нескольких библиотеках РНР, среди которых наибольший интерес представляют следующие: PHPLib Base Library: http://phplib.netuse.de; Richard Hayes's Template Class: http://www.heyes-computing.net; Fast Template: http://www.thewebmasters.net/php. На сайте ресурсов РНР, PHPBuilder (http://www.phpbuilder.com), также имеется несколько интересных учебников, посвященных обработке шаблонов. Кроме того, загляните на сайт РНР Classes Repository (http://phpclasses.UpperDesign.com), здесь также можно найти несколько реализаций. Недостатки системы шаблонов Хотя рассмотренная система шаблонов справляется со своей главной задачей — полным разделением дизайна и программирования, она не лишена недостатков. Некоторые из этих недостатков перечислены ниже. Необоснованные надежды на «идеальное решение» Шаблоны помогают четко выделить в проекте аспекты программирования и дизайна, но они не заменяют нормального взаимодействия между этими аспектами. Более того, правильность их работы зависит от предварительного согласования списка переменных, заменяемых в процессе обработки шаблона. Как и в любом успешном проекте, переходить к написанию кода РНР следует лишь после тщательной проработки спецификации всего приложения. Это значительно уменьшает вероятность ошибок при последующей обработке, приводящих к непредвиденным последствиям при использовании шаблонов. Снижение быстродействия Затраты на обработку файлов приводят к некоторому замедлению работы программы. В какой мере замедляется работа, зависит от ряда факторов, в том числе от размера страницы, размера запроса SQL (если они задействован) и аппаратной конфигурации компьютера. Как правило, эти потери настолько малы, что ими можно пренебречь, но в некоторых ситуациях они оказываются довольно значительными (например, при одновременной обработке нескольких шаблонов в условиях высокого трафика). Ориентация дизайна на РНР Одна из главных целей создания шаблонов заключается в том, чтобы по возможности изолировать дизайнера от программного кода при редактировании внешнего вида и поведения страницы. В идеальном случае дизайнер должен обладать некоторыми навыками программирования или, по крайней мере, быть знакомым с общими концепциями — переменными, циклами и условными командами. Дизайнеру, абсолютно не разбирающемуся в них, применение шаблонов практически ничего не даст, кроме относительно бесполезных сведений из области синтаксиса. В общем, независимо от того, захотите вы пользоваться этим типом шаблонов или нет, я настоятельно рекомендую потратить немного времени и обучить дизайнера азам языка РНР... а еще лучше — купить ему эту книгу! От этого выиграют обе стороны, поскольку дизайнер приобретет дополнительные навыки и станет более ценным членом рабочей группы, а у программиста появится новый источник идей. Может, дизайнер и не изобретет ничего выдающегося, но зато он взглянет на ситуацию под новым углом зрения, обычно недоступным для программиста.

Designed by Fedin
All right reserved
2003-2004
Hosted by uCoz