У вас вопросы?
У нас ответы:) SamZan.net

ЛАБОРАТОРНАЯ РАБОТА 10 РАЗДЕЛЕНИЕ КОДА И ШАБЛОНА ТРАНИЦЫ PHP позволяет комбинировать код программы с

Работа добавлена на сайт samzan.net: 2016-03-13

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 2.2.2025

ЛАБОРАТОРНАЯ РАБОТА №10

РАЗДЕЛЕНИЕ КОДА И ШАБЛОНА ТРАНИЦЫ

PHP позволяет комбинировать код программы с обычным HTML-текстом, что является удобной возможностью, которой все же не стоит злоупотреблять. И особенно в больших сценариях. Это чередование очень плохо смотрится: сначала код, потом — вставки HTML, а затем — опять код. Кроме того, HTML-верстальщику будет крайне трудно понять, где же в этом сценарии именно "его" участки, которые он может править и изменять.

В связи с этим в данной лабораторной работе предлагается отделять почти весь код сценария от текста, задающего внешний вид страницы. А именно — хранить их в разных файлах.

  1.  Идеология

Большинство сценариев пишутся на различных языках программирования без всякого отделения кода от шаблона страницы. Зачем же тогда нам это нужно? Что заставляет нас искать новые пути в Web-программировании? Причина всего одна. Это — желание поручить разработку качественного и сложного сценария сразу нескольким людям, чтобы каждый из них занимался своим делом, которое, как предполагается, он знает лучше всего.

Одна группа людей ("программисты") занимается взаимодействием программы с пользователем и обработкой данных. Другая же группа ("дизайнеры"), наоборот, отвечает лишь за эстетическую часть работы.

Что же получается, если в своих сценариях вы будете смешивать код и оформление сценария? Фактически, его поддержкой и доработкой не сможет заняться никто, кроме Вас самого. В самом деле: программиста будет раздражать постоянно встречающиеся вставки HTML-кода, а дизайнера — опасность случайно изменить какую-нибудь важную функцию программы. Иными словами, такой метод совершенно не подходит при разработке крупных проектов.

  1.  Двухуровневая схема

Итак, мы желаем максимально отделить работу программистов и дизайнеров. Будем делать это не сразу, а постепенно, детализируя ситуацию. Вначале решим более простую проблему: разделим код сценария и шаблон его страницы (что будем называть двухуровневой схемой построения сценария).

  1.  Шаблон страницы

Пусть нам нужно завести новый раздел сайта — гостевую книгу. Выделим для нее отдельный каталог на сервере и создадим в нем файл примерно следующего содержания (листинг 1). Назовем его шаблоном страницы.

Листинг 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 практически невозможно (во всяком случае, без ущерба простоте отладки сценария). Это связано с чрезвычайной слабостью этого интерпретатора в вопросе, касающемся "перехвата" и обработки ошибок во время выполнения кода.

2.2. Генератор данных

Конечно, это еще далеко не весь сценарий. Вы, наверное, заметили, что сердце шаблона — цикл foreach вывода записей — использует непонятно откуда взявшуюся переменную $Book, по контексту — двумерный массив. Кроме того, при отправке формы тоже ведь нужно предусмотреть некоторые действия (а именно, добавление записи в книгу). Мы видим, что где-то должен быть скрыт весь этот код. Он, действительно, располагается в отдельном файле с именем gbook.php. Отличительная черта этого файла — то, что в нем нет никакого намека на то, как нужно форматировать результат работы сценария. Именно поэтому мы называем его генератором данных (листинг 2).

Листинг 2. Генератор данных: gbook.php

<?

define("GBook","gbook.dat"); // имя файла с данными гостевой книги

// Загружает гостевую книгу с диска. Возвращает содержание книги.

function LoadBook($fname)

{ $f=@fopen("gbook.dat","rb"); if(!$f) return array();

$Book=Unserialize(fread($f,100000)); fclose($f);

return $Book;

}

// Сохраняет содержимое книги на диске.

function SaveBook($fname,$Book)

{ $f=fopen("gbook.dat","wb");

fwrite($f,Serialize($Book));

fclose($f);

}

// Исполняемая часть сценария.

// Сначала — загрузка гостевой книги.

$Book=LoadBook(GBook);

// Обработка формы, если сценарий вызван через нее.

// Если сценарий запущен после нажатия кнопки Добавить...

if(!empty($doAdd)) {

// Добавить в книгу запись пользователя — она у нас хранится

// в массиве $New, см. форму в шаблоне. Запись добавляется,

// как водится, в начало книги.

$Book=array(time()=>$New)+$Book;

Часть V. Приемы программирования на PHP 420

// Записать книгу на диск.

SaveBook(GBook,$Book);

}

// Все. Теперь у нас в $Book хранится содержимое книги в формате:

// array (

// время_добавления => array(

// (или id) name => имя_пользователя,

// text => текст_пользователя

// ),

// . . .

// );

// Вот теперь загружаем шаблон страницы.

include "gbook.htm";

?>

Как видим, исполняемая часть довольно небольшая и, действительно, занимается лишь подготовкой данных для их последующего вывода в шаблоне. Шаблон рассматривается этой составляющей как обычный PHP-файл, который она подключает при помощи инструкции include. Ясно, что весь код шаблона (хотя его и очень мало) выполнится в том же контексте, что и генератор данных, а значит, ему будет доступна переменная $Book.

Логически весь код можно разбить на 3 части. Первая из них — задание конфигурации сценария, в нашем случае она состоит всего лишь в определении одной-единственной константы GBook, хранящей имя файла гостевой книги. Во второй части, которую можно назвать "прикладным интерфейсом" гостевой книги, содержатся описания функций, достаточных для работы с гостевой книгой. Это, конечно, функции загрузки и сохранения наполнения книги на диске. Наконец, третья часть генератора данных обрабатывает запросы пользователей на добавление данных в книгу.

Таким образом, для работы нашего сценария нужны три файла: генератор данных, шаблон книги и файл с записями книги. В принципе, это минимум, если только не привлекать для хранения записей базу данных (что, безусловно, лучше в больших программах). Однако в нашем случае проще как раз работать с файлами.

Обратите внимание: для того чтобы теперь переделать гостевую книгу так, чтобы она использовала базу данных, а не файл, достаточно изменить всего лишь 2 функции: LoadBook() и SaveBook(). Ни других частей генератора данных, ни, тем более, шаблона это не затронет. На самом деле, такой подход не является случайностью: он очень тесно связан с трехуровневой схемой построения интерактивных сценариев, о которой мы скоро будем говорить.

2.3. Взаимодействие генератора данных и шаблона

Вернемся опять к тому же генератору данных. В нем мы проверяем, не запущен ли сценарий книги в ответ на нажатие кнопки Добавить в форме. Если вызвать программу без параметров, то пользователю будет просто выдано содержимое гостевой книги, в противном же случае (то есть при запуске из формы) осуществится добавление записи. Таким образом, мы "одним махом убиваем двух зайцев": используем один и тот же шаблон для двух разных страниц, внешне крайне похожих. Определяем мы, нужно ли добавлять запись, по состоянию переменной $doAdd. Именно такое имя имеет submit-кнопка в форме. Когда ее нажимают, сценарию поступает пара "doAdd=Добавить!", чем мы и воспользовались. Итак, если кнопка нажата, то мы вставляем запись в начало массива $Book и сохраняем его на диске.

Обратите внимание, насколько проста операция добавления записи. Так получилось вследствие того, что мы предусмотрительно дали полям формы с названием и текстом имена, соответственно, New[name] и New[text], которые PHP преобразовал в массив. Вообще говоря, придумывание таких имен для полей — работа скорее программистская, нежели дизайнерская.

В самом коде генератора данных gbook.php в принципе не присутствует никаких данных о внешнем виде нашей гостевой книги. В нем нет ни одной строчки на HTML. Иными словами, генератору совершенно "все равно", как выглядит книга. Он занимается лишь ее загрузкой и обработкой. Это значит, что в будущем для изменения внешнего вида гостевой книги нам не придется править этот код, т. е. мы добились некоторого желаемого разделения труда дизайнера и программиста.

С другой стороны, шаблон gbook.htm не делает никаких предположений о том, как же именно хранится книга на диске и как она обрабатывается. Его дело — "красиво" вывести содержимое массива $Book, "и точка". К тому же он почти не содержит кода на PHP (разве что самый минимум, без которого никак не обойтись). А значит, дизайнеру будет легко изменять внешний вид книги.

2.4. Недостатки

У любой медали есть оборотная сторона и, как часто бывает, от ее качества зависит довольно много. Имеется она и у двухуровневой схемы построения сценариев. Систематизируем все недостатки и постепенно будем их исправлять.

1. Что такое для пользователя "гостевая книга"? Конечно же, это прежде всего страница. А для разработчика сценария? Разумеется, программный код. Получается, что взгляды пользователя несколько отличаются от воззрений разработчика.

Как разрешить сформулированную неувязку? Для этого нужно посмотреть на нашу систему "генератор данных — шаблон" со стороны. Что мы видим? Генератор данных загружает данные с диска, а затем обращается к шаблону, чтобы тот их вывел. Но пользователь хочет иметь перед глазами прежде всего шаблон, а не работу генератора! Мы же заставляем его запускать программу. Возможно, следующее положение и покажется спорным, но на практике оно полностью оправдывает себя. А именно, предлагается поменять направление обмена данными между шаблоном и генератором данных. Пусть шаблон запрашивает данные у генератора, а тот их ему предоставляет. Согласитесь, это укладывается даже в замечательно зарекомендовавшую себя модель обмена "клиент-сервер": шаблон — это клиент, а генератор данных — сервер.

2. Хотя шаблон двухуровневой схемы и является подчиненным элементом, он все же вынужден ссылаться на имя генератора данных через атрибут action тэга <form>. Конечно, это вносит лишь дополнительную неразбериху и является еще одним стимулом к замене понятий "главный" и "подчиненный".

3. Генератор данных состоит из излишне большого числа логических блоков, связанных лишь односторонне. В самом деле, если мы будем писать систему администрирования для нашей гостевой книги, нам опять понадобятся функции загрузки и сохранения данных (то есть, функции LoadBook() и SaveBook()). Поэтому логично будет выделить их в отдельный файл, который будем называть ядром сценария. Ядро — это третий компонент в трехуровневой схеме построения программы, о которой мы сейчас будем говорить. Разумеется, в сложных системах ядро может состоять из десятков (и даже сотен) файлов. Вообще говоря, оно также содержит и сведения о конфигурации (константу GBook), так что часто бывает удобно выделить эти данные в отдельный файл.

Сейчас мы попытаемся решить все эти проблемы.

3. Трехуровневая схема

Итак, в отличие от двухуровневой, трехуровневая схема построения сценария содержит специально выделенный код, или ядро, которое совместно используют все "генераторы данных". Почему последний термин заключен в кавычки? Да потому, что теперь мы будем называть его по-другому, а именно, интерфейсным кодом (или просто интерфейсом) сценария. Генератор данных — по-прежнему сущность, являющаяся объединением ядра и интерфейса.

Кроме того, при использовании трехуровневой схемы пользователь никогда "не видит" генератор данных. Он всегда имеет дело только с шаблоном страницы, который иногда выглядит, как программа. Это происходит при обращении к шаблону (а следовательно, и к генератору данных) из формы в браузере.

3.1. Шаблон страницы

Теперь шаблон сам вызывает генератор, который предоставляет ему нужные данные, а заодно и реагирует на запросы пользователя. Он выполняет это, например, при помощи все той же инструкции include:

Листинг 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>

. . .

Здесь не приводится текст страницы целиком, т. к. после определения формы он идентичен листингу 1. Итак, мы помещаем инструкцию include самой первой строчкой шаблона, и на это есть своя причина. Дело в том, что при различных, скажем так, "аварийных" событиях генератор данных может перенаправить браузер на другой адрес, не вернув управление в шаблон. Конечно, если бы include размещалась где-нибудь в середине шаблона, мы не смогли бы этого сделать, поскольку часть страницы могла быть уже отослана пользователю.

Заметьте, что шаблон имеет расширение HTML и выглядит для пользователя как обычная HTML-страница. Пользователь может и не подозревать, что в действительности сценарий написан на PHP. Но, чтобы описанный механизм заработал, нам необходимо связать расширение HTML с обработчиком PHP. Вот какую строчку нужно добавить в файл .htaccess, расположенный в каталоге (или "надкаталоге") сценария:

AddHandler application/x-httpd-php .html

Мы должны использовать директиву AddHandler, а не AddType, на случай, если для расширения HTML был ранее установлен другой обработчик. Им может быть, например, SSI (Server-Side Includes — Включения на стороне сервера) или даже PHP версии 3. В этом случае директива AddType "не срабатывает".

В действительности обращение из шаблона происходит лишь к интерфейсу сценария, но не к его ядру. Ядро доступно для шаблона лишь посредством общения с интерфейсом, и никак не иначе. В свою очередь, ядро также не может "разговаривать" с шаблоном (во всяком случае, не должно).

Мы видим, что во всех операциях передачи данных неизменно используется "посредник" — интерфейсная часть программы. Это открывает для нас интересные потенциальные возможности (которые на практике задействуются довольно редко). А именно, ядро и шаблон могут в принципе "разговаривать на разных языках", тогда интерфейс будет служить их "переводчиком". Если задуматься, то это и есть главная задача интерфейса.

3.2. Диаграммы двухуровневой и трехуровневой моделей

Пришло время нарисовать схему взаимодействия частей программы при использовании двухуровневой и трехуровневой модели построения, а также еще раз подчеркнуть их различия. Стрелками (рис. 1 и 2) обозначены зависимости, которые можно охарактеризовать словами как "предоставляет данные". Пунктирные стрелки отмечают зависимости, реализуемые достаточно редко. На схемах это не что иное, как переадресация на другую страницу, возможно, выполняемая генератором данных.

Рис. 1. Двухуровневая схема

Мы видим, что в случае двухуровневой схемы связи между компонентами сценария исключительно циклические (см. рис. 1). Каждая часть программы взаимодействует на равных с другой ее частью.

Рис. 2 гораздо сложнее, чем рис. 30.1. Его "загруженность" объясняется тем, что трехуровневая схема более, чем это может показаться с первого взгляда, сложна и универсальна по сравнению с двухуровневой. Обратите внимание на то, что практически все связи стали двусторонними, а циклические — исчезли. Это позволяет работать блокам более независимо, чем для случая двухуровневой модели. А значит, работу над сценарием можно распределить по нескольким исполнителям более эффективно, — к чему мы и стремились.

Единственный блок программы, который не связан с другими двусторонними связями, — файл конфигурации системы. Это неудивительно, ведь конфигурация содержит лишь набор определений констант и переменных, которыми пользуются все остальные блоки схемы. Впрочем, стрелка, ведущая из блока конфигурации в шаблон страницы, хотя и может существовать без особых последствий, все-таки иногда выглядит несколько нелогично. Рекомендуется так строить сценарии, чтобы шаблону не требовалась информация о конфигурации. Он должен обращаться только к данным, сгенерированным интерфейсом.

Рис. 2. Трехуровневая схема

3.3. Интерфейс

Как можно заметить из листинга 4, интерфейс сценария гостевой книги стал гораздо проще, чем это было с генератором данных из листинга 2. Файл, в котором содержится его код, называется точно так же, как и файл генератора. Это и не удивительно: "снаружи" интерфейс выглядит как полноценный генератор данных, а о существовании ядра шаблон даже и не "подозревает".

Листинг 4. Интерфейс: gbook.php

<?

include "kernel.php"; // Загружаем ядро.

$Book=LoadBook(GBook); // Загрузка гостевой книги.

// Обработка формы, если сценарий запущен через нее.

if(!empty($doAdd)) {

// Добавить в книгу запись пользователя.

$Book=array(time()=>$New)+$Book;

// Записать книгу на диск.

SaveBook(GBook,$Book);

}

// Загрузка шаблона не нужна — теперь, наоборот, шаблон

// вызывает интерфейс.

?>

Как видим, интерфейс занимается только той работой, для которой он и предназначен: выступает "посредником" между ядром и шаблоном. Самым первым загружается ядро — файл kernel.php (я люблю так его называть). Дальше осуществляется исключительно обработка и "расшифровка" входных данных и формирование выходных.

3.4. Ядро

Ядро — это самая ответственная, но, на мой взгляд, в то же время и самая скучная часть работы программиста. Действительно, оно напрямую не взаимодействует с шаблоном страницы, а значит, не имеет права "общаться" с пользователем. Ядро в идеале должно содержать лишь набор функций, которые позволяют исчерпывающим образом работать с объектом программы. В этом смысле идеально его объектно-ориентированное построение.

Листинг 5. Ядро: kernel.php

<?

// Загружаем конфигурацию.

include "config.php";

// Загружает гостевую книгу с диска. Возвращает содержимое книги.

function LoadBook($fname)

{ $f=@fopen("gbook.dat","rb");

if(!$f) return array();

$Book=Unserialize(fread($f,100000));

fclose($f);

return $Book;

}

// Сохраняет данные книги на диске.

function SaveBook($fname,$Book)

{ $f=fopen("gbook.dat","wb");

fwrite($f,Serialize($Book));

fclose($f);

}

?>

Действительно, здесь нет ничего, кроме определений функций и еще одной инструкции include (на этот раз последней). Она добавляет конфигурационные данные нашей книги — всего лишь одну-единственную константу GBook, определяющую имя файла, в котором гостевая книга и будет храниться.

Листинг 6. Конфигурация: config.php

<?

define("GBook","gbook.dat"); // имя файла с данными книги

?>

Что же у нас получилось в результате? Мы "растянули" простой сценарий на целых 5 файлов (если считать еще и .htaccess, то на 6). Тут все дело в том, что для простых сценариев (а именно такой мы и рассматривали) трехуровневая схема построения оказывается чересчур уж "тяжеловесной". Что же касается сложных систем, не следует забывать, что "единственность" ядра может сэкономить нам количество файлов, если у комплекса много различных интерфейсов (например, разветвленная система администрирования), не говоря уже о простоте отладки и поддержки. Кроме того, можно полностью разделить работу по написанию ядра и интерфейса между несколькими людьми.

3.5. Проверка корректности входных данных

До сих пор мы не заботились о том, корректные ли данные заносит посетитель. В нашей ситуации это и не нужно: в книгу кто угодно может добавлять любую информацию. В то же время в реальной жизни, конечно, приходится проверять правильность введенных пользователем данных. Например, мы можем ввести в нашу гостевую книгу цензуру, которая будет запрещать пользователям употреблять в сообщениях ненормативную лексику. Конечно, при вводе недопустимого текста он не должен добавиться в гостевую книгу; вместо этого в браузер пользователя хотелось бы вывести предупреждение. Но как осуществить желаемую модерацию в соответствии с трехуровневой схемой? И какая часть программы должна за это отвечать?

На второй вопрос ответить довольно просто. Так как ядро не в состоянии "общаться" с шаблоном напрямую, а шаблон не может исполнять сложный код, остается единственный вариант — интерфейс. А что касается того, как выводить сообщение об ошибке, — вопрос довольно спорный. Мы рассмотрим лишь самое простое решение.

Интерфейс должен сгенерировать сообщение и передать его шаблону. Последний, "заметив" сообщение, может вывести текст контрастными буквами, например, вверху страницы. С этим никаких проблем быть не должно. Пусть интерфейс в случае ошибки создает переменную $Error и присваивает ей текст ошибки. Вот как может выглядеть шаблон:

. . .

<?if(Isset($Error)) {?>

<h3><font color=red>Произошла ошибка: <?=$Error?></font></h3>

<?}?>

. . .

Задания

Ыполнить задание к 8-й лабораторной работе, ипользя трехронею хем разделения шаблона и кода траницы.




1. Туристические культурно-исторические ресурсы РФ
2. ~ Процес встановлення драйвера та програмного забезпечення бездротового мережного адаптера
3. Екологічна криза
4. Оптические преобразователи сигнала
5. идея мировой разум Субъективный идеализмотрицает наличие какойлибо реальности вне сознания субъек
6. всего лишь версия но и она показывает что во всеобщем шапкозакидательском угаре потерялось самое важное- с
7. Региональное управление и территориальное планирование
8. ПОПИТ
9. Здесь убийцы охотятся за талантливыми людьми дабы добывать из их костей нечто подчиняющее себе человеческ
10. глобальные проблемы вошел в международный лексикон во второй половине 60х г