- Создание объектов классов, инкапсуляция, Конструкторы, Деструкторы
admin 28 Февраля 2006 в 16:44:23
Классы, объекты и объявления методов
Классы образуют синтаксическую базу объектно-ориентированного программирования. Их можно рассматривать как своего рода «контейнеры» для логически связанных данных и функций (обычно называемых методами — см. ниже). Класс представляет собой шаблон, по которому создаются конкретные экземпляры, используемые в программе. Экземпляры классов называются объектами.
Чтобы лучше понять связь между классами и объектами, можно представить класс как «чертеж» для создания объектов. По чертежу «изготавливаются» разные объекты, обладающие одними и теми же базовыми характеристиками (например, при строительстве дома — одна дверь, два окна и определенная толщина стены). Тем не менее, каждый объект существует независимо от других — изменение его характеристик никак не влияет на характеристики других объектов; например, в уже построенном доме можно прорубить дополнительное окно. Важно помнить, что у объектов все равно остается общая характеристика — количество окон.
Класс также можно рассматривать как тип данных (см. главу 2), а объект — как переменную (по аналогии с тем, как переменная $counter относится к целому, а переменная $last_name — к строковому типу). Программа может одновременно работать с несколькими объектами одного класса как с несколькими переменными целого типа. Общий формат классов РНР приведен в листинге 6.1.
Листинг 6.1. Объявление классов в РНР
Подведем итоги: объявление класса должно начинаться с ключевого слова class (подобно тому, как объявление функции начинается с ключевого слова function). Каждому объявлению атрибута, содержащегося в классе, должно предшествовать ключевое слово van. Атрибуты могут относиться к любому типу данных, поддерживаемых в РНР; их можно рассматривать как переменные с небольшими различиями, о которых вы узнаете в этой главе. После объявлений атрибутов следуют объявления методов, очень похожие на типичные объявления функций.
По общепринятым правилам имена классов ООП начинаются с прописной буквы, а все слова в именах методов, кроме первого, начинаются с прописных букв (первое слово начинается со строчной буквы). Разумеется, вы можете использовать любые обозначения, которые сочтете удобными; главное — выберите стандарт и придерживайтесь его.
Методы часто используются для работы с атрибутами классов. При ссылках на атрибуты внутри методов используется специальная переменная $this. Синтаксис методов продемонстрирован в следующем примере:
Переменная $this ссылается на экземпляр объекта, для которого вызывается метод. Поскольку в любом классе может существовать несколько экземпляров объектов, уточнение $this необходимо для ссылок на атрибуты, принадлежащие текущему объекту. При использовании этого синтаксиса обратите внимание на два обстоятельства:
атрибут, на который вы ссылаетесь в методе, не нужно передавать в виде параметра функции;
знак доллара ($) ставится перед переменной $this, но не перед именем атрибута (как у обычной переменной).
Создание объектов и работа с ними
Объекты создаются оператором new. Например, объект класса Webpage создается следующей командой:
Новый объект с именем $some_page обладает собственным набором атрибутов и методов, перечисленных в классе Webpage. Для изменения значения атрибута $bgcolor, принадлежащего этому конкретному объекту, можно воспользоваться определенным в классе методом setBgColor( ):
Следует помнить, что РНР также позволяет явно получить значение атрибута указанием имен объекта и атрибута:
Однако второй способ противоречит принципу инкапсуляции, и при работе с ООП поступать так не следует. Чтобы понять, почему это так, прочитайте следующий раздел.
Нарушение инкапсуляции
Допустим, вы создали класс, один из атрибутов которого представляет собой массив. Но вместо того чтобы работать с массивом через промежуточные методы (например, предназначенные для создания, удаления, модификации элементов и т. д.), вы в случае необходимости напрямую обращаетесь к массиву. В течение месяца вы уверенно программируете большое «объектно-ориентированное» приложение и благосклонно принимаете хвалу коллег-программистов. Будущее сулит много радостей — премии, оплачиваемый отпуск и даже отдельный кабинет.
Но вот через месяц после успешного запуска вашего web-приложения ваш начальник вдруг решает, что массивы в данном случае не годятся и работать с информацией нужно только через базу данных.
Какая неприятность! Поскольку вы решили работать с атрибутами напрямую, вам теперь придется просматривать всю программу и везде, где происходят обращения к данным, вносить исправления в соответствии с новым интерфейсом. Задача весьма хлопотная, к тому же чревата риском внесения новых ошибок.
А теперь давайте посмотрим, что произошло бы при работе с данными с использованием методов. Все, что вам пришлось бы сделать при переходе от массива к базе данных — перепрограммировать методы. Модификация автоматически распространяется на все точки программы, в которых присутствуют вызовы методов.
Конструкторы
Довольно часто при создании объекта требуется задать значения некоторых атрибутов. К счастью, разработчики технологии ООП учли это обстоятельство и реализовали его в концепции конструкторов. Конструктор представляет собой метод, который задает значения некоторых атрибутов (а также может вызывать другие методы). Конструкторы вызываются автоматически при создании новых объектов. Чтобы это стало возможным, имя метода-конструктора должно совпадать с именем класса, в котором он содержится. Пример конструктора приведен в листинге 6.2.
Листинг 6.2. Использование конструктора
Раньше создание объекта и инициализация атрибутов выполнялись раздельно. Конструкторы позволяют выполнить эти действия за один этап.
Интересная подробность: в зависимости от количества передаваемых параметров могут вызываться разные конструкторы. Например, в листинге 6.2 объекты класса Webpage могут создаваться двумя способами. Во-первых, вы можете вызвать конструктор, который просто создает объект, но не инициализирует его атрибуты:
Во-вторых, объект можно создать при помощи конструктора, определенного в классе, — в этом случае вы создаете объект класса Webpage и присваиваете значение его атрибуту bgcolor:
Деструкторы
Как упоминалось ранее, в РНР отсутствует непосредственная поддержка деструкторов. Тем не менее, вы можете легко имитировать работу деструктора, вызывая функцию РНР unset( ). Эта функция уничтожает содержимое переменной и возвращает занимаемые ею ресурсы системе. С объектами unset( ) работает так же, как и с переменными. Допустим, вы работаете с объектом $Webpage. После завершения работы с этим конкретным объектом вызывается функция
Эта команда удаляет из памяти все содержимое $Webpage. Действуя в духе инкапсуляции, можно поместить вызов unset( ) в метод с именем destroy( ) и затем вызвать его:
Помните: необходимость в вызове деструкторов возникает лишь при работе с объектами, использующими большой объем ресурсов, поскольку все переменные и объекты автоматически уничтожаются по завершении сценария.
Классы образуют синтаксическую базу объектно-ориентированного программирования. Их можно рассматривать как своего рода «контейнеры» для логически связанных данных и функций (обычно называемых методами — см. ниже). Класс представляет собой шаблон, по которому создаются конкретные экземпляры, используемые в программе. Экземпляры классов называются объектами.
Чтобы лучше понять связь между классами и объектами, можно представить класс как «чертеж» для создания объектов. По чертежу «изготавливаются» разные объекты, обладающие одними и теми же базовыми характеристиками (например, при строительстве дома — одна дверь, два окна и определенная толщина стены). Тем не менее, каждый объект существует независимо от других — изменение его характеристик никак не влияет на характеристики других объектов; например, в уже построенном доме можно прорубить дополнительное окно. Важно помнить, что у объектов все равно остается общая характеристика — количество окон.
Класс также можно рассматривать как тип данных (см. главу 2), а объект — как переменную (по аналогии с тем, как переменная $counter относится к целому, а переменная $last_name — к строковому типу). Программа может одновременно работать с несколькими объектами одного класса как с несколькими переменными целого типа. Общий формат классов РНР приведен в листинге 6.1.
Листинг 6.1. Объявление классов в РНР
<?
class Class_name {
var $attribute_1;
...
var $attribute_N;
function function1() {
...
}
...
function functionN() {
...
} // end Class_name
?>
Подведем итоги: объявление класса должно начинаться с ключевого слова class (подобно тому, как объявление функции начинается с ключевого слова function). Каждому объявлению атрибута, содержащегося в классе, должно предшествовать ключевое слово van. Атрибуты могут относиться к любому типу данных, поддерживаемых в РНР; их можно рассматривать как переменные с небольшими различиями, о которых вы узнаете в этой главе. После объявлений атрибутов следуют объявления методов, очень похожие на типичные объявления функций.
По общепринятым правилам имена классов ООП начинаются с прописной буквы, а все слова в именах методов, кроме первого, начинаются с прописных букв (первое слово начинается со строчной буквы). Разумеется, вы можете использовать любые обозначения, которые сочтете удобными; главное — выберите стандарт и придерживайтесь его.
Методы часто используются для работы с атрибутами классов. При ссылках на атрибуты внутри методов используется специальная переменная $this. Синтаксис методов продемонстрирован в следующем примере:
<?
class Webpage {
var $bgcolor;
function setBgColor($color) {
$this->bgcolor = $color;
}
function getBgColor() {
return $this->bgcolor;
}
}
?>
Переменная $this ссылается на экземпляр объекта, для которого вызывается метод. Поскольку в любом классе может существовать несколько экземпляров объектов, уточнение $this необходимо для ссылок на атрибуты, принадлежащие текущему объекту. При использовании этого синтаксиса обратите внимание на два обстоятельства:
атрибут, на который вы ссылаетесь в методе, не нужно передавать в виде параметра функции;
знак доллара ($) ставится перед переменной $this, но не перед именем атрибута (как у обычной переменной).
Создание объектов и работа с ними
Объекты создаются оператором new. Например, объект класса Webpage создается следующей командой:
<? $home_page = new Webpage; ?>
Новый объект с именем $some_page обладает собственным набором атрибутов и методов, перечисленных в классе Webpage. Для изменения значения атрибута $bgcolor, принадлежащего этому конкретному объекту, можно воспользоваться определенным в классе методом setBgColor( ):
<? $some_page->setBgColor("black"); ?>
Следует помнить, что РНР также позволяет явно получить значение атрибута указанием имен объекта и атрибута:
<? $some_page->bgcolor; ?>
Однако второй способ противоречит принципу инкапсуляции, и при работе с ООП поступать так не следует. Чтобы понять, почему это так, прочитайте следующий раздел.
Нарушение инкапсуляции
Допустим, вы создали класс, один из атрибутов которого представляет собой массив. Но вместо того чтобы работать с массивом через промежуточные методы (например, предназначенные для создания, удаления, модификации элементов и т. д.), вы в случае необходимости напрямую обращаетесь к массиву. В течение месяца вы уверенно программируете большое «объектно-ориентированное» приложение и благосклонно принимаете хвалу коллег-программистов. Будущее сулит много радостей — премии, оплачиваемый отпуск и даже отдельный кабинет.
Но вот через месяц после успешного запуска вашего web-приложения ваш начальник вдруг решает, что массивы в данном случае не годятся и работать с информацией нужно только через базу данных.
Какая неприятность! Поскольку вы решили работать с атрибутами напрямую, вам теперь придется просматривать всю программу и везде, где происходят обращения к данным, вносить исправления в соответствии с новым интерфейсом. Задача весьма хлопотная, к тому же чревата риском внесения новых ошибок.
А теперь давайте посмотрим, что произошло бы при работе с данными с использованием методов. Все, что вам пришлось бы сделать при переходе от массива к базе данных — перепрограммировать методы. Модификация автоматически распространяется на все точки программы, в которых присутствуют вызовы методов.
Конструкторы
Довольно часто при создании объекта требуется задать значения некоторых атрибутов. К счастью, разработчики технологии ООП учли это обстоятельство и реализовали его в концепции конструкторов. Конструктор представляет собой метод, который задает значения некоторых атрибутов (а также может вызывать другие методы). Конструкторы вызываются автоматически при создании новых объектов. Чтобы это стало возможным, имя метода-конструктора должно совпадать с именем класса, в котором он содержится. Пример конструктора приведен в листинге 6.2.
Листинг 6.2. Использование конструктора
<?
class Webpage {
var $bgcolor;
function Webpage($color) {
$this->bgcolor = $color;
}
}
// Вызвать конструктор класса Webpage
$page = new Webpage("brown");
?>
Раньше создание объекта и инициализация атрибутов выполнялись раздельно. Конструкторы позволяют выполнить эти действия за один этап.
Интересная подробность: в зависимости от количества передаваемых параметров могут вызываться разные конструкторы. Например, в листинге 6.2 объекты класса Webpage могут создаваться двумя способами. Во-первых, вы можете вызвать конструктор, который просто создает объект, но не инициализирует его атрибуты:
<? $page = new Webpage; ?>
Во-вторых, объект можно создать при помощи конструктора, определенного в классе, — в этом случае вы создаете объект класса Webpage и присваиваете значение его атрибуту bgcolor:
<? $page = new Webpage("brown"); ?>
Деструкторы
Как упоминалось ранее, в РНР отсутствует непосредственная поддержка деструкторов. Тем не менее, вы можете легко имитировать работу деструктора, вызывая функцию РНР unset( ). Эта функция уничтожает содержимое переменной и возвращает занимаемые ею ресурсы системе. С объектами unset( ) работает так же, как и с переменными. Допустим, вы работаете с объектом $Webpage. После завершения работы с этим конкретным объектом вызывается функция
<? unset($Webpage); ?>
Эта команда удаляет из памяти все содержимое $Webpage. Действуя в духе инкапсуляции, можно поместить вызов unset( ) в метод с именем destroy( ) и затем вызвать его:
<? $Website->destroy( ); ?>
Помните: необходимость в вызове деструкторов возникает лишь при работе с объектами, использующими большой объем ресурсов, поскольку все переменные и объекты автоматически уничтожаются по завершении сценария.
|