Деловая неделя

Используя шаблон «Дефрагментация» (или «Строитель»), вы складываете все промежуточные результаты работы функций в один общий массив, а другие функции используют потом эти результаты вместо приёма параметров

ЕЖЕНЕДЕЛЬНАЯ РЕКЛАМНАЯ ГАЗЕТА ДЛЯ ПРЕДПРИЯТИЙ «Деловая неделя» (Иркутск)

Шаблон проектирования «Дефрагментация»

Речь идёт о построении html-страницы с помощью php-скрипта. Возможно, более продуктивной аналогией здесь было бы строительство дома. Но немного хромает последовательность: дом нельзя строить с крыши, а дефрагментация предполагает заполнение пустых мест где попало (кусочек окна, кусочек пола, кусочек кровли...). Поэтому идеальной аналогией будет собирание паззла, на котором изображён дом. Правда, лифт в этом доме (навигация) будет переносить посетителей не на другой этаж, а в другой дом (находящийся, может быть, в другом государстве). Ну, а шаблон можно назвать и «Строитель». Или даже «Торрент» (тоже по кусочкам заполняет скачиваемый файл).

Перед отправкой пользователю текста страницы мы должны отправлять ещё и HTTP-заголовки для браузера. Потому что, строго говоря, мы строим не страницу, а HTTP-ответ на запрос браузера. И в этом ответе, в частности, должна быть указана длина текста страницы. Ну, или хотя бы хэш (etag). Ни того ни другого нельзя получить, не имея самой страницы. И то и другое (вообще все заголовки) должно быть отправлено раньше отправки текста страницы. То есть мы должны получить (сгенерировать) полную html-страницу, потом измерить её длину (или вычислить хэш), потом отправить все HTTP-заголовки, потом отправить страницу.

А пока мы отправляем заголовки, текст страницы должен где-то лежать и ждать своей очереди. Не будем же мы извлекать данные из базы и генерировать страницу два раза (для вычисления заголовков и для отправки самого текста)! Ну, где лежать – с этим проблем нет. Пишем $page = "Готовый текст страницы";, потом используем переменную $page для вычисления заголовков, потом пишем print $page;. То есть храним текст в переменной (для этого и нужны переменные).

Одной переменной, однако, будет недостаточно. Дело в том, что такие несовпаденья во времени (необходимость в повторном обращении к отдельным элементам конструкции) возникают достаточно часто. И для хранения нескольких элементов (или нескольких десятков) нужна более сложная структура. Например, массив. Массив появляется в системе строительства ещё раньше (раньше потребности временно сохранить что-то полученное из базы и частично обработанное). Он возникает из потребности хранить шаблоны.

В «классическом» варианте шаблонизатора шаблон хранится в отдельном html-файле с метками вида %вставь_текст% (которые при обработке заменяются нужными данными). То есть в чистом виде это должно быть примерно так: в файле шаблона написано <body>%вставь_текст%</body>, мы извлекаем из базы Текст и командой str_replace впихиваем в шаблон. Но чистота разрушается, например, тем фактом, что заголовок страницы обычно хранится в отдельном поле таблицы с данными. То есть должно быть что-то более сложное:

Ну, и ещё несколько разных элементов. Но мы пока не вышли за пределы «линейного» (одноуровневого) шаблона. А придётся. В тексте страницы ведь может быть, например, список отзывов пользователей, или список анонсов новостей. А у каждого элемента списка – свой шаблон:

– где список анонсов, в свою очередь, делается в цикле из отдельного шаблона:

Из своих отдельных шаблонов делаются также пункты меню, разные элементы разных форм, разные типы сообщений (например, об ошибках)... Нет никакого смысла хранить всё это в куче отдельных маленьких файлов. Вот и возникает «предопределённый» массив (определённый до начала извлечения данных из базы). Это одна часть строительного материала – более-менее крупные заготовки (блоки) и отдельные «кирпичи».

Другая часть – описание данных, извлекаемых из БД (тут трудно подобрать строительную аналогию). Например, русские наименования полей или типы сортировки. При формировании из данных HTML-таблицы нужно, например, назначать ширину колонок и указывать в заголовке таблицы наименования полей. Ширину колонок можно назначать с помощью classname элементов col. Наименования полей – в строке заголовка таблицы. Массив с описанием структуры данных один. Зачем проходить его два раза для формирования заголовка таблицы (для формирования colgroup и thead)?

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

1. Шаблон:

2. Подготовка данных для шаблона:

Здесь $cols и $cells – две простые переменные, которые хранят данные очень короткое время: сразу после их заполнения вызывается функция, соединяющая данные с шаблоном, создающая готовый строительный фрагмент более высокого уровня. И вот этот более крупный фрагмент уже сохраняется в массиве (в котором, кроме заголовка таблицы, есть ещё тело таблицы, а также другие элементы HTML-страницы). Когда весь массив уровня страницы заполняется, данные соединяются с основным шаблоном (страницы), и текст страницы готов, его можно отправлять пользователю.

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

***

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

Понятно, что тут сразу высвечивается другая проблема: возможность отсутствия такого «внешнего», не передаваемого явно функции параметра (что в определённых случаях порождает ошибки). Ну, надо или инициализировать в начале главный массив со всеми значениями (в том числе пустыми), или пытаться получать из него значения специальной функцией, которая будет сначала проверять наличие индекса массива.

В наших строительных массивах есть и четвёртая часть (точнее, нулевая) – переменные среды. В каком-то фреймворке нам встретилась очень знакомая функция извлечения переменных окружения (с последовательными попытками получить их из $_SERVER, $_ENV и другими способами). Но это была именно пустая, «абстрактная» функция, предполагающая, видимо, что в случае необходимости с её помощью можно будет получить какой-нибудь HTTP_REFERER. У нас же эта функция отрабатывает один раз в цикле и складывает все полученные значения всё в тот же массив (типа реестр). Если потом «вдруг» понадобится какой-то не обработанный функцией и не сложенный в реестр параметр среды, то... будет ошибка. Вот именно таких «вдруг» не должно быть в хорошо отлаженной системе, правая рука должна точно знать, что делает левая – мы таки планируем общую стуктуру скриптов сайта!

D.M., admin

Читать все комментарии (0)

Добавить комментарий:

*Автор:
E-Mail:
*Текст: