Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

web - tec / PHP 5 для начинающи

.pdf
Скачиваний:
71
Добавлен:
12.06.2015
Размер:
26.79 Mб
Скачать

632 Глава 16

Рис. 16.25.

Упражнения

Следующие упражнения помогут читателям попрактиковаться в использовании рассмотренных выше методик и применить их в реальных разработках. Решения для этих упражнений приведены в Приложении A.

1.Создайте PHP+сценарий, который открывает файл изображения и добавляет в изображение черную рамку толщиной в один пиксель.

2.Используя функции disk_total_space()и disk_free_space(), покажите графическим способом объем используемого пространства на жестком диске.

17

Учебный пример: диспетчер протоколирования на PHP

К этому времени читатель имеет хорошие теоретические знания о PHP+програм+ мировании. В предыдущих главах рассматривались различные темы и понятия, вклю+ чая хорошие методики программирования, объектно+ориентированное программи+ рование, PEAR и основы программирования, такие как условные операторы, типы данных, область видимости и структура кода. В этой, последней главе рассмотренные аспекты PHP+программирования связываются в единое целое для создания реального приложения.

Конечно, создание крупного приложения не означает только написание огромного количества кода. Как уже отмечалось, создание высококачественного программного обеспечения предполагает большой объем планирования и всестороннее обдумыва+ ние задачи. В этой главе представлен учебный пример в формате цикла разработки программного обеспечения. В дополнение к этому в главе предлагается введение в шаблоны Smarty, описаны возможности и методики их применения.

Сначала разработчик рассматривает приложение в понятиях постановки задачи и анализирует возможности ее решения. После того как выбран подходящий метод реализации решения, начинается разработка программы. В ходе разработки придется определять, как создаваемые классы и объекты будут работать вместе и формировать решение. В главе 13 рассматривалось использование языка UML. В этой главе на ста+ дии проектирования приложения также используется UML.

В главе изучаются жизненно важные вопросы реализации кода и исследуется весь код, который используется для выполнения необходимых задач. Полный листинг ко+ да в главе не приводится, поскольку он был бы чрезмерно длинным, но все работаю+ щее приложение можно загрузить с Web+сайта Wrox.

634 Глава 17

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

Итак, приступим к изучению учебного примера.

Почему именно диспетчер протоколирования?

В наши дни многие компании и даже частные лица имеют по несколько Web+ сайтов. Например, многие издательства создают отдельные Web+сайты для каждого из своих изданий. Причины у всех разные, но важно то, что компании часто считают обязательным накапливать информацию, полученную от нескольких Web+сайтов. На+ пример, если издательство предлагает зарегистрированным пользователям всех сайтов скидку на все свои книги, то маркетинговому отделу для формирования бюджета, веро+ ятно, понадобится список всех пользователей, которым предоставляется эта скидка.

Существует множество разных мнений относительно типов технологий, которые следует применять для создания Web+сайтов. Поэтому весьма вероятно, что информа+ ция, хранящаяся в базах данных или серверных журналах каждого из этих сайтов, значительно отличается форматом или даже на более низком уровне ++++++ типом дан+ ных. Попытки извлечь регистрационные данные, просматривая серверные журналы или записи баз данных, на практике могут потребовать больших затрат времени.

Даже если предположить, что кому+нибудь действительно понадобилось решить эту задачу, то одного только получения всей информации, вероятно, было бы недос+ таточно для отдела маркетинга. Сотрудники, которым понадобилась эта информация, скорее всего хотели бы получить ее в унифицированном читабельном формате. По+ лучение журналов сервера, смешанных с записями из нескольких разных баз данных, могло бы сбивать с толку, потому что в отчетах, разбросанных по разным таблицам, была бы посторонняя информация. Форматирование всех этих данных вручную так+ же потребовало бы значительного объема работы.

Еще хуже, что такую работу, возможно, придется выполнять каждые несколько ме+ сяцев, чтобы согласовывать данные о новых книгах. Повторяющаяся работа такого рода определенно должна быть автоматизирована, но как все+таки решить проблему?

Короткий ответ ++++++ протоколировать информацию, полученную от каждого посети+ теля на каждом Web+сайте непосредственно во время ввода. Это, несомненно, поможет систематизировать необходимую информацию, и на каждом сайте можно было бы га+ рантировать, что информация накапливается в стандартном формате ++++++ например, в CSV+файлах. Это не самое плохое решение, но оно все равно предполагает посещение каждого сайта для сбора необходимой информации. Но даже в этом случае CSV+файлы не самые удобные для чтения, и маркетологи, вероятно, были бы недовольны, если бы вся нужная им информация предоставлялась в виде одного массивного CSV+файла.

Кроме того, возникает риск дублирования больших объемов информации, потому что один человек может быть зарегистрирован на нескольких сайтах. Попытки про+ верять каждого пользователя по журналам и базам данных других сайтов перед вставкой

Учебный пример: диспетчер протоколирования на 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 ("Не удалось подключиться к базе данных!");

Учебный пример: диспетчер протоколирования на PHP 637

}

mysql_select_db($db_name);

$sql = "SELECT DISTINCT userposition FROM user";

$res = mysql_query($sql); $results = array(); $i=0;

while ($pos=mysql_fetch_row($res)) { $results[$i++] = $pos[0];

}

$smarty->assign('results', $results); $smarty->display('index.tpl');

?>

2.Теперь создайте новый файл, назовите его index.tpl и сохраните в нем сле+ дующий код:

<HTML>

<BODY>

<B>Перечень позиций игроков: </B><BR><BR> {section name=position loop=$results} {$results[position]}<BR>

{/section}

</BODY>

</HTML>

3.Вызовите в Web+браузере страницу index.php; результат должен быть похож на рис. 17.1.

Рис. 17.1.

Как это работает

PHP+сценарий начинается с подключения класса Smarty и создания нового Smarty+объекта:

<?php

require 'Smarty.class.php'; $smarty = new Smarty;

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, вы сможете разобраться с особенностями использования системы в описы+ ваемом учебном примере.

640 Глава 17

PHPUnit

Получить самую свежую версию пакета PHPUnit можно по адресу http://sourceforge/net/projects/phpunit/. После загрузки пакета и его раз+ мещения в каком+либо каталоге необходимо убедиться, что файл phpunit.php досту+ пен PHP, поэтому путь к выбранному каталогу нужно указать в параметре include_path в php.ini. Если изменять php.ini нежелательно, то можно установить пакет в тот же каталог, в котором расположен тестируемый код.

Рассмотрим практическое применение пакета PHPUnit.

Работа с PHPUnit

В рамках одного небольшого раздела невозможно рассмотреть все функции PHPUnit, однако, имея базовые знания, читатель может самостоятельно поэкспериментиро+ вать с различными классами пакета.

Во+первых, PHPUnit предоставляет функции, которые можно использовать для проверки определенных условий. Например, требуется определить, какое значение возвращает заданный метод, true или false. Чтобы это сделать, необходимо сфор+ мулировать утверждение об этом методе и проверить, является ли оно верным. Для проверки правильности утверждений PHPUnit предоставляет метод assert():

function assert($boolean, $message=0) { if (! $boolean)

$this->fail($message);

}

Например, чтобы для проверки открытия соединения с базой данных, может ис+ пользоваться следующая функция:

function isOpen($db){ If ($db == null){

return false;

}

return true;

}

Зная, что функция isOpen() возвращает булево значение, можно использовать функцию assert() так:

$this->assert(isOpen($db)), "Соединение не создано!");

Функция assert() не единственная используемая функция в PHPUnit, а кроме того, существуют разные варианты ее применения (хотя пока это все, что требуется знать об использовании методов PHPUnit).

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

1.Для формирования контекста, в котором можно будет запускать тесты, необхо+ димо создать класс, расширяющий класс TestCase пакета PHPUnit:

class MultiLogTestSuite extends TestCase

Учебный пример: диспетчер протоколирования на 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, потому что само по себе умение использовать блочные тесты име+ ет определенную ценность.

Теперь, имея необходимые базовые знания, можно приступать к созданию и тес+ тированию учебного примера.

Проектирование диспетчера протоколирования

Прежде чем браться за написание кода приложения, необходимо многое обдумать. Начиная новый проект, нужно в первую очередь ответить на следующие вопросы.

Чего вы пытаетесь добиться?

Как вы собираетесь это сделать?

Для любого разрабатываемого приложения стоит обдумать несколько различных аспектов. Например, как будет реализована проверка и обработка ошибок, и нужно ли реализовать какую+либо систему безопасности?

В данном случае особая система безопасности не требуется, потому что приложе+ ние не будет записывать информацию с кредитных карт или другие секретные сведе+ ния. По существу, в учебном примере рассматривается протоколирование таких данных,

Соседние файлы в папке web - tec