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

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

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

542 Глава 13

$res = mysql_query($sql, DataManager::_getConnection());

if(! ($res && mysql_num_rows($res))) {

die("Не удалось получить данные для email-адреса $emailID");

}

return mysql_fetch_assoc($res);

}

}

?>

Класс DataManager предоставляет структуры данных, используемые для наполне+ ния массива $data в подклассах класса PropertyObject. Существуют отдельные функции, возвращающие данные каждого типа. Впоследствии в этот класс будут до+ бавлены еще несколько новых функций.

Все методы класса объявлены как статические. Статические методы требуют, что+ бы все переменные экземпляров были также статическими. Чтобы использовать ме+ тоды статического класса, не нужно создавать экземпляр этого класса. В определен+ ных ситуациях это имеет смысл. Например, класс Math предоставляет такие методы, как squareRoot(), power() и cosine(), и имеет свойства, среди которых есть ма+ тематические константы e и pi. Все экземпляры этого класса выполняют одинаковые вычисления. Квадратный корень 2 не изменяется, число 4 в кубе всегда будет равно 64, а две упомянутые константы всегда будут оставаться константами. Нет необходимости создавать отдельные экземпляры этого класса, поскольку его состояние и свойства не изменяются никогда. Класс Math, реализованный таким образом, должен давать воз+ можность вызывать все его функции статически.

Класс DataManager почти такой же. Все его функции самодостаточны, а все пере+ менные экземпляра, с которыми они взаимодействуют, являются статическими. Класс не предоставляет своим пользователям никаких свойств. Таким образом, методы класса можно вызывать с помощью оператора статических методов ::. Поскольку все созданные методы являются статическими, не нужно создавать объект с помощью оператора $obj = new DataManager(); вместо этого можно использовать синтаксис вроде DataManager::getEmail().

Следует отметить использование статической переменной функции в частном ме+ тоде _getConnection(). (Использование статических переменных функций обсуж+ далось в главе 6.)

Классы Entity, Individual и Organization

Имея все поддерживающие классы, можно перейти к ядру приложения ++++++ к классу Entity и его подклассам.

Прежде всего необходимо обновить UML+диаграмму и внести изменения в иерархию объектов. Все классы кроме DataManager, который не является производным от какого+ либо другого класса, созданы как подклассы PropertyObject. Класс PropertyObject реализует абстрактный интерфейс, который называется Validator. Новая UML+ диаграмма показана на рис. 13.12.

Работа с UML и классами 543

PropertyObject

DataManager

Validator

Address

PhoneNumber

Entity

Email

 

 

 

 

 

 

 

 

 

 

 

 

Individual

 

 

Organization

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 13.12.

Теперь можно начинать разрабатывать классы Entity, Individual и Organization. Следующий код представляет собой полностью реализованный класс Entity:

<?php require_once('class.PropertyObject.php'); require_once('class.PhoneNumber.php'); require_once('class.Address.php'); require_once('class.EmailAddress.php');

abstract class Entity extends PropertyObject {

private $_emails; private $_addresses; private $_phonenumbers;

public function __construct($entityID) {

$arData = DataManager::getEntityData($entityID); parent::__construct($arData);

544 Глава 13

$this->propertyTable['entityid'] = 'entityid'; $this->propertyTable['id'] = 'entityid'; $this->propertyTable['name1'] = 'sname1'; $this->propertyTable['name2'] = 'sname2'; $this->propertyTable['type'] = 'ctype';

$this->_emails = DataManager::getEmailObjectsForEntity($entityID); $this->_addresses = DataManager::getAddressObjectsForEntity($entityID); $this->_phonenumbers =

DataManager::getPhoneNumberObjectsForEntity($entityID);

}

function setID($val) {

throw new Exception('Изменение значения поля id не допускается!');

}

function setEntityID($val) { $this->setID($val);

}

function phonenumbers($index) {

if(!isset($this->_phonenumbers[$index])) {

throw new Exception('Указан некорректный номер телефона!'); } else {

return $this->_phonenumbers[$index];

}

}

function getNumberOfPhoneNumbers() { return sizeof($this->_phonenumbers);

}

function addPhoneNumber(PhoneNumber $phone) { $this->_phonenumbers[] = $phone;

}

function addresses($index) {

if(!isset($this->_addresses[$index])) {

throw new Exception('Указан неправильный адрес!'); } else {

return $this->_addresses[$index];

}

}

function getNumberOfAddresses() { return sizeof($this->_addresses);

}

function addAddress(Address $address) { $this->_addresses[] = $address;

}

function emails($index) {

if(!isset($this->_emails[$index])) {

throw new Exception('Указан неправильный email-адрес!'); } else {

return $this->_emails[$index];

}

}

function getNumberOfEmails() { return sizeof($this->_emails);

}

Работа с UML и классами 545

function addEmail(Email $email) { $this->_emails[] = $email;

}

public function validate() {

//Общие процедуры проверки корректности данных

}

}

?>

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

Класс Entity объявлен как абстрактный, потому что сам по себе он бесполезен. Все объекты являются объектами либо класса Individual, либо Organization. Соз+ давать объекты класса Entity бессмысленно. Объявление класса как абстрактного препятствует созданию объектов этого класса.

В код были добавлены обращения к нескольким новым функциям класса DataManager: getEntityData() и get[x]ObjectsForEntity. Функция getEntityData() возвра+ щает данные, необходимые для создания объекта, так же как рассмотренные выше функции для обработки типов контактной информации. Ниже приведен код новых функций в файле class.DataManager.php:

//для краткости начало файла здесь не показывается

...

die("Невозможно получить данные для телефона $phoneID");

}

return pg_fetch_assoc($res);

}

public static function getEntityData($entityID) {

$sql = "SELECT * FROM entities WHERE entityid = $entityID"; $res = mysql_query($sql, DataManager::_getConnection()); if(! ($res && mysql_num_rows($res))) {

die("Failed getting entity $entityID");

}

return mysql_fetch_assoc($res);

}

?>

Чтобы добавить функции get[x]ObjectsForEntity, необходимо поместить сле+ дующий код в конец файла class.DataManager.php сразу после объявления функ+ ции getEntityData:

public static function getAddressObjectsForEntity($entityID) {

$sql = "SELECT addressid from entityaddress WHERE entityid = $entityID"; $res = mysql_query($sql, DataManager::_getConnection());

if(!$res) {

die("Невозможно получить адресные данные для записи $entityID");

}

if(mysql_num_rows($res)) { $objs = array();

while($rec = mysql_fetch_assoc($res)) { $objs[] = new Address($rec['addressid']);

}

546 Глава 13

return $objs;

}else {

return array();

}

}

public static function getEmailObjectsForEntity($entityID) {

$sql = "SELECT emailid from entityemail WHERE entityid = $entityID"; $res = mysql_query($sql, DataManager::_getConnection());

if(!$res) {

die("Невозможно получить email-адрес для записи $entityID");

}

if(mysql_num_rows($res)) { $objs = array();

while($rec = mysql_fetch_assoc($res)) { $objs[] = new EmailAddress($rec['emailid']);

}

return $objs;

}else {

return array();

}

}

public static function getPhoneNumberObjectsForEntity($entityID) { $sql = "SELECT phoneid from entityphone WHERE entityid = $entityID"; $res = mysql_query($sql, DataManager::_getConnection());

if(!$res) {

die("Невозможно получить номер телефона для записи $entityID");

}

if(mysql_num_rows($res)) { $objs = array();

while($rec = mysql_fetch_assoc($res)) { $objs[] = new PhoneNumber($rec['phoneid']);

}

return $objs;

}else {

return array();

}

}

Все эти функции принимают в качестве параметра идентификатор записи. Они выполняют запрос к базе данных, чтобы определить, существуют ли для указанной за+ писи номера телефонов, а также e+mail+ и почтовые адреса. Если это так, функции соз+ дают массив объектов EmailAddress, Address или PhoneNumber, передавая иден+ тификатор соответствующему конструктору. Затем созданный массив возвращается объекту Entity, где он сохраняется в соответствующей частной переменной.

Класс Entity выполняет всю основную работу, поэтому остается только реализо+ вать классы Individual и Organization. Создайте файл class.Individual.php

и введите в него следующий код:

<?php require_once('class.Entity.php');

require_once('class.Organization.php');

class Individual extends Entity {

public function __construct($userID) {

Работа с UML и классами 547

parent::__construct($userID);

$this->propertyTable['firstname'] = 'name1'; $this->propertyTable['lastname'] = 'name2';

}

public function __toString() {

return $this->firstname . ' ' . $this->lastname;

}

public function getEmployer() {

return DataManager::getEmployer($this->id);

}

public function validate() { parent::validate();

//специальная проверка данных частного лица

}

}

?>

Коротко и ясно. Класс Individual устанавливает несколько новых свойств, кото+ рые упрощают доступ к имени и фамилии частного лица и позволяют не использовать довольно неудобные свойства name1 и name2, определенные в классе Entity. Кроме того, в классе также определяется новый метод, getEmployer(), которому требуется новая функция в классе DataManager. Эта функция будет рассматриваться при опи+ сании класса Organization, код которого представлен ниже. Создайте файл с име+ нем class.Organization.php и введите в него следующий код:

<?php require_once('class.Entity.php'); require_once('class.Individual.php');

class Organization extends Entity {

public function __construct($userID) { parent::__construct($userID);

$this->propertyTable['name'] = 'name1';

}

public function __toString() { return $this->name;

}

public function getEmployees() {

return DataManager::getEmployees($this->id);

}

public function validate() {

parent::validate();

//специальная проверка данных организации

}

}

?>

548 Глава 13

Этот класс благодаря эффективности наследования также довольно прост. Объяв+ ляется свойство name, которое упрощает получение названия организации (свойство sname2 для организаций не используется).

Чтобы добавить в класс DataManager функции getEmployer() и getEmployee(), необходимо добавить следующий код в конец файла class.DataManager.php:

public static function getEmployer($individualID) {

$sql = "SELECT organizationid FROM entityemployee " . "WHERE individualid = $individualID";

$res = mysql_query($sql, DataManager::_getConnection());

if(! ($res && mysql_num_rows($res))) {

die("Невозможно получить данные о работодателе для $individualID");

}

$row = mysql_fetch_assoc($res);

if($row) {

return new Organization($row['organizationid']); } else {

return null;

}

}

public static function getEmployees($orgID) {

$sql = "SELECT individualid FROM entityemployee " . "WHERE organizationid = $orgID";

$res = mysql_query($sql, DataManager::_getConnection());

if(! ($res && mysql_num_rows($res))) {

die("Невозможно получить данные о работнике для $orgID");

}

if(pg_num_rows($res)) { $objs = array();

while($row = mysql_fetch_assoc($res)) {

$objs[] = new Individual($row['individualid']);

}

return $objs; } else {

return array();

}

}

Две эти функции зависят от присутствия таблицы entityemployee, которая по+ казана ниже:

CREATE TABLE entityemployee ( individualid int NOT NULL, organizationid int NOT NULL,

CONSTRAINT fk_entityemployee_individualid

FOREIGN KEY (individualid) REFERENCES entity(entityid), CONSTRAINT fk_entityemployee_organizationid

FOREIGN KEY (organizationid ) REFERENCES entity(entityid)

);

Эта таблица связывает частных лиц с организациями, в которых они работают. Соответствующие функции класса DataManager аналогичны уже описанным.

Чтобы заставить систему работать, необходима еще одна последняя функция ++++++

getAllEntitiesAsObjects(), метод класса DataManager, который перечисляет все записи в базе. Этот метод завершает всю работу, которую необходимо выполнять в объектах:

Работа с UML и классами 549

public static function getAllEntitiesAsObjects() { $sql = "SELECT entityid, type from entities";

$res = mysql_query($sql, DataManager::_getConnection());

if(!$res) {

die("Невозможно получить все записи");

}

if(mysql_num_rows($res)) { $objs = array();

while($row = mysql_fetch_assoc($res)) { if($row['type'] == 'I') {

$objs[] = new Individual($row['entityid']);

}elseif ($row['type'] == 'O') {

$objs[] = new Organization($row['entityid']);

}else {

die("Неизвестный тип записи {$row['type']}!");

}

}

return $objs;

}else {

return array();

}

}

Класс DataManager позволяет перечислить все записи с контактной информаци+ ей в системе. Он проверяет значение поля ctype в таблице entity, чтобы опреде+ лить, к какому типу относится запись ++++++ частное лицо или организация, а затем созда+ ет объект соответствующего типа и добавляет его в массив, который возвращает описываемая функция.

Использование системы

К этому моменту уже становится очевидной реальная эффективность объектно+ ориентированного подхода. В результате выполнения следующего кода (test.php) отображается подробный перечень всех контактных сведений в базе данных:

<?php

require_once('class.DataManager.php'); //включаем весь

//необходимый код

function println($data) { print $data . "<br>\n";

}

$arContacts = DataManager::getAllEntitiesAsObjects(); foreach($arContacts as $objEntity) {

if(get_class($objEntity) == 'Individual') {

print "<h1>Частное лицо - {$objEntity->__toString()}</h1>";

} else {

print "<h1>Организация - {$objEntity->__toString()}</h1>";

}

if($objEntity->getNumberOfEmails()) { //Есть e-mail-адреса. Выводим заголовок

print "<h2>Email-адреса</h2>";

for($x=0; $x < $objEntity->getNumberOfEmails(); $x++) { println($objEntity->emails($x)->__toString());

}

}

if($objEntity->getNumberOfAddresses()) { //Есть почтовые адреса.

print "<h2>Адреса</h2>";

for($x=0; $x < $objEntity->getNumberOfAddresses(); $x++) {

550 Глава 13

println($objEntity->addresses($x)->__toString());

}

}

if($objEntity->getNumberOfPhoneNumbers()) { //Есть номера телефонов.

print "<h2>Телефоны</h2>";

for($x=0; $x < $objEntity->getNumberOfPhoneNumbers(); $x++) { println($objEntity->phonenumbers($x)->__toString());

}

}

print "<hr>\n";

}

?>

В браузере страница должна выглядеть так, как показано на рис. 13.13 (естественно, данные в таблицах будут отличаться).

Рис. 13.13.

Работа с UML и классами 551

Используя всего лишь 36 строк кода, можно отобразить почти всю информацию по записям в системе. Здесь не показаны сведения о работодателях и работниках, это зада+ ние остается в качестве упражнения читателю. Строка, в которой вызывается функция get_class, должна подсказать, какой класс используется, т.е. какая функция вызывает+ ся ++++++ getEmployer() в классе Individual или getEmployees() в классе Organization.

Резюме

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

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

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

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