MyCMS - система управления сайтом для рядовых пользователей

MyCMS / Попытки / Теория создания CMS / 1.1. Конструкторы и деструкторы

Конструкторы и деструкторы.

Как бы кто не любил объектно-ориентированное программирование, существует еще и понятие объектно-ориентированное проектирование. И как бы нам не хотелось обойтись без него, но проектировать мы будем в рамках «объектов», а реализовывать такие вещи тоже лучше в рамках «объектов».

Что можно отнести к минусам ООП в PHP – скорость.


При проведении простого теста (Apache 1.3.27 (Win32), PHP 4.3.3, MS Win XP, CPU PIII-633, RAM-256Mb, HDD-7200rpm, в дальнейшем все результаты тестов будут приводиться при этой конфигурации, если не указано другой). Выяснилось, что разница во времени между подключениями файлов построенных на классах и файлов без классов ~ 15% (не в пользу ООП). А разница в скорости запуска функций 25% (вновь не в пользу ООП). Но чтобы так сильно не пугать Вас переведем проценты в секунды, и получаем, что ООП файлы подключаются на ~0,0008 секунды медленнее, нежели файлы не использующие ООП, а функции вызываются на ~0,00008 с. То есть отставание исчисляется в десятитысячных и стотысячных долях секунды, на далеко не самой быстрой и не самой оптимальной конфигурации сервера. К сожалению, я не проводил тестов на PHP 5.* и на реальном сервере, но вы можете это сделать, самостоятельно используя приведенный код (для запуска кода Вам нужно будет создать директорию с исходником, создав там две пустые подпапки “v0” и “v1”, изменяя константу MAX в бОльшую сторону вы сможете ярче заметить разницу в скорости выполнения, для точного определения тест следует провести несколько раз).

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

Единственным весомым препятствием на данном этапе в ООП программировании на PHP для Вас может послужить не привычка. Но как показывает опыт, люди быстро переучиваются в таких вещах и поняв однажды все плюсы такого программирования в дальнейшем их сложно заставить программировать «по старинке».

Объектов как таковых в PHP 4 нет (Ввиду того, что абсолютное большинство хостеров рунета на данный момент предлагает тарифы с PHP 4, все примеры и особенности проектирования будут приводиться исходя из тонкостей PHP 4). Но есть классы, что, грубо говоря, можно прировнять объектам. Поэтому когда я буду говорить об объектах в контексте PHP, это следует понимать как классы PHP 4.

На этом покончим с введением и приступим к делу.


1. Конструкторы.

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

По большому счету, первой проблемой, которая встает перед разработчиком при работе с классами в PHP 4, это то, что у классов нет своего полноценного указателя на родителя, в отличии скажем от того же Delphi. Следовательно, его следует передать в конструктор. При чем нужно четко представлять себе в каких ситуациях может понадобится данный класс. То есть, понадобится ли он при работе только с системой или же необходмость в нем может возникнуть при работе и с подсистемами (модулями). Если класс использует только свои функции для выполнения всех методов, то тут особой разницы нет, но если класс ссылается на функции системы или какой либо подсистемы, то необходимо проработать вопрос того, чтобы классу были переданы все необходимые указатели.

При создании класса в системе, мы должны предусматривать вариант того, что он может стать основой для нового класса. Например, у нас имеется класс «пользователи». Данный класс имеет все необходимые методы для работы с пользователями, путем подключения всех необходимых подклассов, например, таких как сессия, база данных и т.п. В то же время нам может потребоваться (а нам потребуется) сделать две надстройки на этот класс – это «админская» и «клиентская» версия. То есть, имея базовый класс «пользователи» с базовыми методами по работе с пользователями, мы можем создать два класса – «пользователи админская версия» и «пользователи клиентская версия» extends «пользователи». Как я сказал ранее, базовый класс должен подключить N-подклассов, для чего будет нужна функция инициализации. Предположим, такой функцией является конструктор класса. В таком случае при создании расширения класса, мы получаем ситуацию, что если у расширения имеется свой конструктор, то он может обратиться к конструктору базового класса, только через parent::ClassName() и каждое расширение первой строчкой должно иметь именно эту строку. С одной стороны все лаконично и хорошо, но представим себе ситуацию, что в каждый конструктор (и базовый и расширения) передается некий набор переменных. В таком случае, нам придется придерживаться условия, что набор передаваемых переменных в расширение должен быть не меньше, чем набор передаваемых переменных в базовый класс. А как показывает практика это не всегда удобно, то есть если базовый класс спроектирован так, что в него при инициализации должны передаваться указатели на систему и на модуль, а расширение класса подразумевает передачу указателя только на систему, потому как модуля нет, то неоткуда брать указатель на модуль, то придется «мудрить». Из данной ситуации я практикую выход, который можно описать следующими условиями:

1. Функция инициализации выносится из конструктора.
2. Функция инициализации не принимает никаких переменных.
3. В конструкторе выполняются только действия по занесению в свойства класса переменных, которые были переданы.
4. Имя функции инициализации всегда фиксировано (например _constructor ()).
5. Количество подчеркиваний в имени функции инициализации «_» должно отражать уровень расширения (то есть, для базового класса количество равно 1, для расширения 2, для расширения расширения класса 3 и т.д.). Этот пункт обусловлен тем, что используя parent:: (обращение к базовому классу расширения) не возможно добраться до родителя который является базовым для всей цепочки расширений от расширения 2-ого уровня или выше.
6. Не обязательно для каждого расширения класса создавать функцию инициализации, в большинстве случаев, достаточно родительской функции.


В итоге получаем конструкцию вида:

class Example { var $system; function Example (&$system) { $this->system = &$system; $this->_constructor (); } function _constructor () { /*…*/ } }

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


2. Деструкторы

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

Ввиду того, что в PHP нет деструкторов, нам придется их изобрести путем добавления еще нескольких условий.

1. Деструкторы создаются по условиям принятым для создания функций инициализации.
2. Если экземпляр класса создан как локальная переменная функции, то деструктор должен быть вызван из функции создавшей его.
3. Если экземпляр класса создан как глобальная переменная класса/системы, то вызов должен производиться из деструктора этого класса/системы.
4. Для каждого экземпляра класса должен быть флаг на обновление данных деструктором.

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

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

Условие 4 предназначено для того, чтобы деструктор не делал лишних запросов в базу (если такие в нем присутствуют) мы делаем стандартный флаг update default false и в случае если возникает ситуация, что деструктор экземпляра класса должен выполнить сохранение своих данных в базу мы изменяем флаг экземпляра класса на true. Соответственно, в деструкторе должно быть обрабатывающее условие, а ситуации, когда мы должны сохранить данные экземпляра класса по завершению его работы, нам всегда должны быть известны по определению.

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


3. Заключение.

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


Владимир Бредихин 2006/04/24 01:00

Текущая версия:

MyCMS ver. 2.0.4.39b

Закончена работа:

msk.allcafe.info
Всё о ресторанах Москвы и области

mycms.info
Официальный сайт MyCMS

floraclub.ru
Сайт ресторана «Флора»

naturabisse.ru
Сайт торговой марки "Natura Bisse"

futurapro.allnice.info
Сайт аппарата «FuturaPro»

biooxy.allnice.info
Сайт технологии «Bio Oxygen»


Copyright © MyCMS
Advert: незаметные купольные камеры для слежения ; заказать дизайн полиграфии дизайн студия