web - tec / PHP 5 для начинающи
.pdf17
Учебный пример: диспетчер протоколирования на PHP
К этому времени читатель имеет хорошие теоретические знания о PHP+програм+ мировании. В предыдущих главах рассматривались различные темы и понятия, вклю+ чая хорошие методики программирования, объектно+ориентированное программи+ рование, PEAR и основы программирования, такие как условные операторы, типы данных, область видимости и структура кода. В этой, последней главе рассмотренные аспекты PHP+программирования связываются в единое целое для создания реального приложения.
Конечно, создание крупного приложения не означает только написание огромного количества кода. Как уже отмечалось, создание высококачественного программного обеспечения предполагает большой объем планирования и всестороннее обдумыва+ ние задачи. В этой главе представлен учебный пример в формате цикла разработки программного обеспечения. В дополнение к этому в главе предлагается введение в шаблоны Smarty, описаны возможности и методики их применения.
Сначала разработчик рассматривает приложение в понятиях постановки задачи и анализирует возможности ее решения. После того как выбран подходящий метод реализации решения, начинается разработка программы. В ходе разработки придется определять, как создаваемые классы и объекты будут работать вместе и формировать решение. В главе 13 рассматривалось использование языка UML. В этой главе на ста+ дии проектирования приложения также используется UML.
В главе изучаются жизненно важные вопросы реализации кода и исследуется весь код, который используется для выполнения необходимых задач. Полный листинг ко+ да в главе не приводится, поскольку он был бы чрезмерно длинным, но все работаю+ щее приложение можно загрузить с Web+сайта Wrox.
Учебный пример: диспетчер протоколирования на PHP 635
записи выглядят просто нелепо. Поэтому, скорее всего, решение будет связано с не+ обходимостью создания центрального сервера для протоколирования информа+ ции ++++++ это в частности означает, что для вставки новой записи потребовалось бы сде+ лать всего одну проверку.
Предположим, решение принято: требуется приложение, принимающее инфор+ мацию от различных Web+сайтов, протоколирующее, а затем трансформирующее ее
вудобочитаемый формат. Решение проблемы форматирования еще не рассматрива+ лось в книге, но те читатели, которые использовали Smarty+шаблоны, скорее всего, будут уверены, что это идеальная ситуация для использования шаблонов с целью вы+ вода информации в удобной и согласованной форме. И они будут правы. Разрабаты+ ваемое приложение позволит опрашивать центральный сервер с базой данных, кото+ рая в данном случае реализована на основе SQLite. Затем приложение будет выдавать результаты в нескольких предопределенных форматах ++++++ в этой главе для иллюстра+ ции основных принципов рассматривается только два из них, но отчеты можно рас+ ширить с тем, чтобы представлять настолько подробные данные, насколько это необ+ ходимо. Следует помнить о том, что Smarty также можно использовать и в других целях (такие возможности рассматриваются в этой главе далее).
Часть учебного примера представляет собой краткое введение в систему Smarty, так как некоторые из читателей, возможно, не сталкивались с ней раньше. Сущест+ венно облегчает тестирование приложения использование пакета PHPUnit, поэтому
вглаве есть также небольшой раздел, посвященный этому продукту. Читатели, имею+ щие хорошие практические навыки использования Smarty и PHPUnit, могут смело пропустить эти разделы.
Smarty
Почему в этой книге рассматривается Smarty? Тому, кто работал над Web+прило+ жениями как Web+дизайнер, либо как программист, возможно, приходилось модифи+ цировать свой участок кода всякий раз после того, как другой участник проекта изме+ нял свой. Например, разработчик получает HTML+страницы для определенного сайта и в течение недели добавляет PHP+код на уровне представления, чтобы пользователи могли выполнять поиск в таблицах базы данных или отправлять информацию (в зави+ симости от поставленных перед сайтом задач).
Неделю спустя клиент решает изменить внешний вид сайта. Дизайнер страниц раздражен, но переделывает дизайн согласно новым требованиям. Затем он уходит в недельный отпуск, оставляя программисту исправлять ошибки красивого, но со+ вершенно не работающего Web+сайта. Так как весь HTML+код был модифицирован, ни один блок встроенного в Web+страницы PHP+кода не работает так, как должен, по+ этому остается только просматривать код строка за строкой и восстанавливать рабо+ тоспособность приложения.
Гораздо лучше было бы отделить логику представления от бизнес+логики. И здесь система Smarty оказывается весьма полезной.
Установка Smarty
В этом учебном примере будет использоваться система Smarty, поэтому ее необхо+ димо установить. После установки следует убедиться в работоспособности Smarty, за+ пустив небольшой тест. Затем можно приступать к работе над учебным примером.
Ниже описаны этапы установки Smarty.
636Глава 17
1.Загрузите систему шаблонов Smarty с Web+сайта http://smarty.php.net.
2.Распакуйте архив в любой каталог.
3.Убедитесь, что PHP может использовать классы, предоставляемые Smarty. Эти классы расположены в каталоге libs инсталляции Smarty. Добавьте абсолют+ ный путь к этому каталогу в переменную include_path в файле php.ini:
include_path = ".;c:\php5\includes;c:\php5\pear;C:\Program Files\ Smarty-2.6.2\libs"
4.Естественно, Smarty+классы можно рассматривать как любые другие PHP+ классы и подключать их по отдельности в .php+файлы, например:
require('C:\Program Files\Smarty-2.6.2\libs\Smarty.class.php'); $smarty = new Smarty;
Используя Smarty, необходимо учитывать некоторые обстоятельства. Для работы Smarty требуется наличие четырех каталогов, которые (по умолчанию) называются templates, templates_c, configs и cache. Эти имена можно явно определить в фай+ ле Smarty.class.php ++++++ каждое из них содержится в соответствующей переменной: $template_dir, $compile_dir, $config_dir, $cache_dir. Убедитесь, что Web+ сервер имеет права на запись в каталог $compile_dir (templates_c по умолчанию).
Документация рекомендует создавать отдельную группу таких каталогов для каждого приложения, использующего Smarty.
С целью обеспечения безопасности сайтов рекомендуется располагать эти катало+ ги за пределами корневого каталога Web+сайта. Web+браузеры ни при каких обстоя+ тельствах не должны получать доступ к этим каталогам.
Следующий краткий пример позволяет убедиться, что Smarty работает корректно.
Практика Использование Smarty
В этом примере создается шаблон, позволяющий представить полученную из MySQL+таблицы информацию в виде аккуратно отформатированного списка. Для это+ го создается один .php+файл, ответственный за создание подключения к базе данных, выполнение запросов и возвращение результатов в Smarty+шаблон. Затем шаблон форматирует информацию, полученную данным PHP+сценарием, с помощью одной из встроенных в Smarty функций.
1.Сохраните следующий код в файле с именем index.php. Для работы сценария необходим доступ к таблице user, которая упоминалась в главах 11++++13, либо можно создать отдельную таблицу специально для этого сценария:
<?php
require 'Smarty.class.php'; $smarty = new Smarty;
$hostname = "localhost"; $db_user = "phpuser"; $db_pass = "phppass"; $db_name = "sample_db";
// подключение к базе данных
$conn = mysql_connect($hostname, $db_user, $db_pass);
if (!$conn){
die ("Не удалось подключиться к базе данных!");
638Глава 17
Впоследующем коде очень немного нововведений. Создается MySQL+подключение, а если подключение невозможно, то обеспечивается завершение работы программы с выдачей сообщения об ошибке:
$hostname = "localhost"; $db_user = "phpuser"; $db_pass = "phppass"; $db_name = "sample_db";
// подключение к базе данных
$conn = mysql_connect($hostname, $db_user, $db_pass);
if (!$conn){
die ("Не удалось подключиться к базе данных!");
}
mysql_select_db($db_name);
Затем формируется SQL+запрос, который будет использоваться для получения не+ обходимых результатов из базы данных. Так как требуется создать список не всех запи+ сей, а только уникальных игровых позиций, используется ключевое слово DISTINCT. Затем результаты вставляются в массив:
$sql = "SELECT DISTINCT userposition FROM user"; $res = mysql_query($sql);
$results = array(); $i=0;
while ($pos=mysql_fetch_row($res)) { $results[$i++] = $pos[0];
}
Весьма интересна завершающая часть сценария. Результаты присваиваются пере+ менной шаблона (в данном случае она называется results), а затем отображается шаблон (index.tpl):
$smarty->assign('results', $results); $smarty->display('index.tpl');
?>
Это конец PHP+сценария, поэтому теперь можно перейти собственно к шаблону, файлу index.tpl. Код шаблона начинается со стандартных HTML+тегов и краткого поясняющего текста:
<HTML>
<BODY>
<B>Перечень позиций игроков: </B><BR><BR>
В программной части шаблона используется функция section для обработки мас+ сива результатов в цикле. Для этой функции атрибуты name и loop являются обяза+ тельными. В рассматриваемом примере цикл выполняется до тех пор, пока в массиве $results есть необработанные значения. Значение атрибута name функции section должно быть указано рядом с именем переменной в фигурных скобках :
{section name=position loop=$results} {$results[position]}<BR>
{/section}
Код шаблона завершается закрывающими HTML+тегами:
</BODY>
</HTML>
Также следует отметить, что сгенерированный PHP+файл сохраняется в каталоге templates_c. Этот файл является результатом работы шаблона. Нет необходимости разбираться в коде, который содержится в этом файле, ++++++ он представлен здесь толь+ ко для наглядности:
Учебный пример: диспетчер протоколирования на PHP 639
<?php /* Smarty version 2.6.2, created on 2004-04-12 21:22:51 compiled from index.tpl */ ?>
<HTML>
<BODY>
<B>Перечень позиций игроков: </B><BR><BR> <?php if (isset($this->_sections['position'])) unset($this->_sections['position']);
$this->_sections['position']['name'] = 'position'; $this->_sections['position']['loop'] = is_array($_loop=$this- >_tpl_vars['results']) ? count($_loop) : max(0, (int)$_loop); unset($_loop); $this->_sections['position']['show'] = true; $this->_sections['position']['max'] = $this->_sections['position']['loop']; $this->_sections['position']['step'] = 1; $this->_sections['position']['start'] = $this->_sections['position']['step'] > 0 ? 0 : $this->_sections['position']['loop']-1;
if ($this->_sections['position']['show']) { $this->_sections['position']['total'] = $this->_sections['position']['loop'];
if ($this->_sections['position']['total'] == 0) $this->_sections['position']['show'] = false;
} else
$this->_sections['position']['total'] = 0; if ($this->_sections['position']['show']):
for ($this->_sections['position']['index'] = $this->_sections['position']['start'], $this->_sections['position']['iteration'] = 1; $this->_sections['position']['iteration'] <= $this->_sections['position']['total']; $this->_sections['position']['index'] += $this->_sections['position']['step'], $this->_sections['position']['iteration']++): $this->_sections['position']['rownum'] = $this->_sections['position']['iteration']; $this->_sections['position']['index_prev'] = $this->_sections['position']['index'] - $this->_sections['position']['step']; $this->_sections['position']['index_next'] = $this->_sections['position']['index'] + $this->_sections['position']['step']; $this->_sections['position']['first'] = ($this->_sections['position']['iteration'] == 1); $this->_sections['position']['last'] = ($this->_sections['position']['iteration'] == $this- >_sections['position']['total']);
?> <?php echo $this->_tpl_vars['results'][$this->_sections['position'] ['index']]; ?>
<BR>
<?php endfor; endif; ?> </BODY>
</HTML>
Этим примером завершается вводный материал по системе шаблонов Smarty. Бо+ лее подробная информация о Smarty представлена на странице документации проекта http://smarty.php.net/manual/ru/. Теперь, имея достаточное представление о Smarty, вы сможете разобраться с особенностями использования системы в описы+ ваемом учебном примере.
Учебный пример: диспетчер протоколирования на PHP 641
2.Специфический контекст, в котором запускаются тесты, создается путем опре+ деления метода setUp() ++++++ буквально создается среда, в которой будет тести+ роваться код. В рассматриваемом учебном примере в методе setUp(), который впоследствии будет использоваться для запуска тестов, создается два UserLog+ объекта и определяются значения для них. (В действии это будет показано в конце главы в разделе ‘‘Тестирование приложения’’.)
3.Создаются необходимые тесты с именами, которые следуют описанному ниже соглашению:
testMeaningfulName()
testAnotherMeaningfulName()
4. Создается новый комплект тестов:
$suiteOfTests = new TestSuite;
5. В комплект добавляются тесты:
$suiteOfTests->addTest(New MultiLogTestSuite("testMeaningfulName");
$suiteOfTests->addTest(New MultiLogTestSuite("testAnotherMeaningfulName");
6.Создается новый TestRunner+объект. В классе TestRunner просто определена функция run() для запуска всех созданных тестов и вывода отчета о тестировании.
$testRunner = new TestRunner();
7. Наконец, вызывается метод run() (определенный на предыдущем этапе):
$testRunner->run($suiteOfTests);
Это все. Теперь PHPUnit добросовестно выполнит все тесты в комплекте и выве+ дет отчет обо всех результатах (все эти этапы подробно описаны далее в настоящей главе). В этом разделе приведено достаточно сведений для начала работы. После прочтения главы читателю рекомендуется самостоятельно поэкспериментировать с классом PHPUnit, потому что само по себе умение использовать блочные тесты име+ ет определенную ценность.
Теперь, имея необходимые базовые знания, можно приступать к созданию и тес+ тированию учебного примера.
Проектирование диспетчера протоколирования
Прежде чем браться за написание кода приложения, необходимо многое обдумать. Начиная новый проект, нужно в первую очередь ответить на следующие вопросы.
Чего вы пытаетесь добиться?
Как вы собираетесь это сделать?
Для любого разрабатываемого приложения стоит обдумать несколько различных аспектов. Например, как будет реализована проверка и обработка ошибок, и нужно ли реализовать какую+либо систему безопасности?
В данном случае особая система безопасности не требуется, потому что приложе+ ние не будет записывать информацию с кредитных карт или другие секретные сведе+ ния. По существу, в учебном примере рассматривается протоколирование таких данных,