<?include'h.php';?>
<html><head>
		<title>Учебник PHP, Глава 6</title>
		<meta http-equiv="Content-type" content="text/html; charset=Windows-1251">
		</head>
		
      <DIV class=infotxt>
      <LI><A href="#a">Глава 6. 
      Объектно-ориентированные возможности PHP</A> 
      <UL>
        <LI><A href="#b">PHP и ООП</A> 
        <LI><A href="#c">Классы, объекты и 
        объявления методов</A> 
        <UL>
          <LI><A href="#d">Создание объектов и 
          работа с ними</A> 
          <LI><A href="#e">Нарушение 
          инкапсуляции</A> 
          <LI><A href="#f">Конструкторы</A> 
          <LI><A href="#g">Деструкторы</A> 
          <LI><A href="#h">Простое и иерархическое 
          наследование</A> 
          <LI><A href="#i">Абстрактные классы</A> 
          <LI><A href="#j">Перегрузка методов</A> 
          </LI></UL>
        <LI><A href="#k">Функции для работы с 
        классами и объектами</A> 
        <LI><A href="#l">Итоги</A> </LI></UL>
      <UL></UL><A name=a></A>
      <P>&nbsp;</P>
      <P>ГЛАВА 6</P>
      <P>Объектно-ориентированные возможности РНР</P>
      <P>Если вы ориентируетесь в современных технологиях программирования, 
      объектно-ориентированное программирование (ООП) наверняка является частью 
      вашей повседневной работы. Если же вы принадлежите к числу новичков в 
      области ООП, после чтения этой главы и рассмотрения нескольких примеров 
      программирование предстанет перед вами совсем в новом свете. Эта глава 
      посвящена технологии ООП и ее реализации в РНР. В ней описан весь 
      необходимый синтаксис и приводятся примеры, которые позволят вам заняться 
      созданием объектно-ориентированных приложений.</P>
      <P>Стратегию ООП лучше всего описать как смещение приоритетов в процессе 
      программирования от функциональности приложения к структурам данных. Это 
      позволяет программисту моделировать в создаваемых приложениях реальные 
      объекты и ситуации. Технология ООП обладает тремя главными 
      преимуществами:</P>
      <UL>
        <LI>она проста для понимания — ООП позволяет мыслить категориями 
        повседневных объектов; 
        <LI>повышенно надежна и проста для сопровождения — правильное 
        проектирование обеспечивает простоту расширения и модификации 
        объектно-ориентированных программ. Модульная структура позволяет вносить 
        независимые изменения в разные части программы, сводя к минимуму риск 
        ошибок программирования; 
        <LI>ускоряет цикл разработки — модульность и здесь играет важную роль, 
        поскольку различные компоненты ОО-программ можно легко использовать в 
        других программах, что уменьшает избыточность,кода и снижает риск 
        внесения ошибок при копировании. </LI></UL>
      <P>Специфика ООП заметно повышает эффективность труда программистов и 
      позволяет им создавать более мощные, масштабируемые и эффективные 
      приложения. Многие преимущества ООП обусловлены одним из его 
      фундаментальных принципов — инкапсуляцией. Инкапсуляцией называется 
      включение различных мелких элементов в более крупный объект, в результате 
      чего программист работает непосредственно с этим объектом. Это приводит к 
      упрощению программы, поскольку из нее исключаются второстепенные 
      детали.</P>
      <P>Инкапсуляцию можно сравнить с работой автомобиля с точки зрения 
      типичного водителя. Многие водители не разбираются в подробностях 
      внутреннего устройства машины, но при этом управляют ею именно так, как 
      было задумано. Пусть они не знают, как устроен двигатель, тормоз или 
      рулевое управление, — существует специальный интерфейс, который 
      автоматизирует и упрощает эти сложные операции. Сказанное также относится 
      к инкапсуляции и ООП — многие подробности «внутреннего устройства» 
      скрываются от пользователя, что позволяет ему сосредоточиться на решении 
      конкретных задач. В ООП эта возможность обеспечивается классами, объектами 
      и различными средствами выражения иерархических связей между ними (классы 
      и объекты рассматриваются ниже).</P>
      <P><A href="http.html://doks.gorodok.net/0" name=b></A>РНР и ООП</P>
      <P>Хотя РНР обладает общими объектно-ориентированными возможностями, он не 
      является полноценным ОО-языком (например, таким, как C++ или Java). В 
      частности, в РНР не поддерживаются следующие объектно-ориентированные 
      возможности:</P>
      <UL>
        <LI>множественное наследование; 
        <LI>автоматический вызов конструкторов (если вы хотите, чтобы при 
        конструировании объекта производного класса вызывался конструктор 
        базового класса, вам придется вызвать его явно); 
        <LI>абстрактные классы; 
        <LI>перегрузка методов; 
        <LI>перегрузка операторов (это связано с тем, что РНР является языком со 
        свободной типизацией, — за дополнительной информацией обращайтесь к 
        главе 2); 
        <LI>закрытый и открытый доступ, виртуальные функции; 
        <LI>деструкторы; 
        <LI>полиморфизм. </LI></UL>
      <P>Но и без всего перечисленного вы все равно сможете извлечь пользу из 
      объектно-ориентированных возможностей, поддерживаемых РНР. Реализация ООП 
      в РНР оказывает колоссальную помощь в модульном оформлении 
      функциональности вашей программы.</P>
      <P><A name=c></A>Классы, объекты и объявления методов</P>
      <P>Классы образуют синтаксическую базу объектно-ориентированного 
      программирования. Их можно рассматривать как своего рода «контейнеры» для 
      логически связанных данных и функций (обычно называемых методами — см. 
      ниже). Класс представляет собой шаблон, по которому создаются конкретные 
      экземпляры, используемые в программе. Экземпляры классов называются 
      объектами.</P>
      <P>Чтобы лучше понять связь между классами и объектами, можно представить 
      класс как «чертеж» для создания объектов. По чертежу «изготавливаются» 
      разные объекты, обладающие одними и теми же базовыми характеристиками 
      (например, при строительстве дома — одна дверь, два окна и определенная 
      толщина стены). Тем не менее, каждый объект существует независимо от 
      других — изменение его характеристик никак не влияет на характеристики 
      других объектов; например, в уже построенном доме можно прорубить 
      дополнительное окно. Важно помнить, что у объектов все равно остается 
      общая характеристика — количество окон.</P>
      <P>Класс также можно рассматривать как тип данных (см. главу 2), а объект 
      — как переменную (по аналогии с тем, как переменная $counter относится к 
      целому, а переменная $last_name — к строковому типу). Программа может 
      одновременно работать с несколькими объектами одного класса как с 
      несколькими переменными целого типа. Общий формат классов РНР приведен в 
      листинге 6.1.</P>
      <P>Листинг 6.1. Объявление классов в РНР</P>
      <P>class Class_name {&nbsp;</P>
      <P>var $attribute_1;</P>
      <P>...</P>
      <P>var $attribute_N;</P>
      <P>function function1() {</P>
      <P>...</P>
      <P>}</P>
      <P>...</P>
      <P>function functionN() {</P>
      <P>...</P>
      <P>} // end Class_name</P>
      <P>Подведем итоги: объявление класса должно начинаться с ключевого слова 
      class (подобно тому, как объявление функции начинается с ключевого слова 
      function). Каждому объявлению атрибута, содержащегося в классе, должно 
      предшествовать ключевое слово van. Атрибуты могут относиться к любому типу 
      данных, поддерживаемых в РНР; их можно рассматривать как переменные с 
      небольшими различиями, о которых вы узнаете в этой главе. После объявлений 
      атрибутов следуют объявления методов, очень похожие на типичные объявления 
      функций.</P>
      <P>По общепринятым правилам имена классов ООП начинаются с прописной 
      буквы, а все слова в именах методов, кроме первого, начинаются с прописных 
      букв (первое слово начинается со строчной буквы). Разумеется, вы можете 
      использовать любые обозначения, которые сочтете удобными; главное — 
      выберите стандарт и придерживайтесь его.</P>
      <P>Методы часто используются для работы с атрибутами классов. При ссылках 
      на атрибуты внутри методов используется специальная переменная $this. 
      Синтаксис методов продемонстрирован в следующем примере:</P>
      <P>&lt;?</P>
      <P>class Webpage {</P>
      <P>van $bgcolor;</P>
      <P>function setBgColor($color) {</P>
      <P>$this-&gt;bgcolor = $color;</P>
      <P>}</P>
      <P>function getBgColor() {</P>
      <P>return $this-&gt;bgcolor;</P>
      <P>}</P>
      <P>}</P>
      <P>?&gt;</P>
      <P>Переменная $this ссылается на экземпляр объекта, для которого 
      вызывается метод. Поскольку в любом классе может существовать несколько 
      экземпляров объектов, уточнение $this необходимо для ссылок на атрибуты, 
      принадлежащие текущему объекту. При использовании этого синтаксиса 
      обратите внимание на два обстоятельства:</P>
      <P>атрибут, на который вы ссылаетесь в методе, не нужно передавать в виде 
      параметра функции;</P>
      <P>знак доллара ($) ставится перед переменной $this, но не перед именем 
      атрибута (как у обычной переменной).</P>
      <P><A name=d></A>Создание объектов и работа с ними</P>
      <P>Объекты создаются оператором new. Например, объект класса Webpage 
      создается следующей командой:</P>
      <P>$home_page = new Webpage;</P>
      <P>Новый объект с именем $some_page обладает собственным набором атрибутов 
      и методов, перечисленных в классе Webpage. Для изменения значения атрибута 
      $bgcolor, принадлежащего этому конкретному объекту, можно воспользоваться 
      определенным в классе методом setBgColor( ):</P>
      <P>$some_page-&gt;setBgColor("black");</P>
      <P>Следует помнить, что РНР также позволяет явно получить значение 
      атрибута указанием имен объекта и атрибута:</P>
      <P>$some_page-&gt;bgcolor;</P>
      <P>Однако второй способ противоречит принципу инкапсуляции, и при работе с 
      ООП поступать так не следует. Чтобы понять, почему это так, прочитайте 
      следующий раздел.</P>
      <P><A name=e></A>Нарушение инкапсуляции</P>
      <P>Допустим, вы создали класс, один из атрибутов которого представляет 
      собой массив. Но вместо того чтобы работать с массивом через промежуточные 
      методы (например, предназначенные для создания, удаления, модификации 
      элементов и т. д.), вы в случае необходимости напрямую обращаетесь к 
      массиву. В течение месяца вы уверенно программируете большое 
      «объектно-ориентированное» приложение и благосклонно принимаете хвалу 
      коллег-программистов. Будущее сулит много радостей — премии, оплачиваемый 
      отпуск и даже отдельный кабинет.</P>
      <P>Но вот через месяц после успешного запуска вашего web-приложения ваш 
      начальник вдруг решает, что массивы в данном случае не годятся и работать 
      с информацией нужно только через базу данных.</P>
      <P>Какая неприятность! Поскольку вы решили работать с атрибутами напрямую, 
      вам теперь придется просматривать всю программу и везде, где происходят 
      обращения к данным, вносить исправления в соответствии с новым 
      интерфейсом. Задача весьма хлопотная, к тому же чревата риском внесения 
      новых ошибок.</P>
      <P>А теперь давайте посмотрим, что произошло бы при работе с данными с 
      использованием методов. Все, что вам пришлось бы сделать при переходе от 
      массива к базе данных — перепрограммировать методы. Модификация 
      автоматически распространяется на все точки программы, в которых 
      присутствуют вызовы методов.</P>
      <P><A name=f></A>Конструкторы</P>
      <P>Довольно часто при создании объекта требуется задать значения некоторых 
      атрибутов. К счастью, разработчики технологии ООП учли это обстоятельство 
      и реализовали его в концепции конструкторов. Конструктор представляет 
      собой метод, который задает значения некоторых атрибутов (а также может 
      вызывать другие методы). Конструкторы вызываются автоматически при 
      создании новых объектов. Чтобы это стало возможным, имя 
      метода-конструктора должно совпадать с именем класса, в котором он 
      содержится. Пример конструктора приведен в листинге 6.2.</P>
      <P>Листинг 6.2. Использование конструктора</P>
      <P>&lt;?</P>
      <P>class Webpage {&nbsp;</P>
      <P>var $bgcolor;</P>
      <P>function Webpage($color) {</P>
      <P>$this-&gt;bgcolor = $color;</P>
      <P>}</P>
      <P>}</P>
      <P>// Вызвать конструктор класса Webpage</P>
      <P>$page = new Webpage("brown");</P>
      <P>?&gt;</P>
      <P>Раньше создание объекта и инициализация атрибутов выполнялись 
      раздельно. Конструкторы позволяют выполнить эти действия за один этап.</P>
      <P>Интересная подробность: в зависимости от количества передаваемых 
      параметров могут вызываться разные конструкторы. Например, в листинге 6.2 
      объекты класса Webpage могут создаваться двумя способами. Во-первых, вы 
      можете вызвать конструктор, который просто создает объект, но не 
      инициализирует его атрибуты:</P>
      <P>$page = new Webpage;</P>
      <P>Во-вторых, объект можно создать при помощи конструктора, определенного 
      в классе, — в этом случае вы создаете объект класса Webpage и присваиваете 
      значение его атрибуту bgcolor:</P>
      <P>$page = new Webpage("brown");</P>
      <P><A name=g></A>Деструкторы</P>
      <P>Как упоминалось ранее, в РНР отсутствует непосредственная поддержка 
      деструкторов. Тем не менее, вы можете легко имитировать работу 
      деструктора, вызывая функцию РНР unset( ). Эта функция уничтожает 
      содержимое переменной и возвращает занимаемые ею ресурсы системе. С 
      объектами unset( ) работает так же, как и с переменными. Допустим, вы 
      работаете с объектом $Webpage. После завершения работы с этим конкретным 
      объектом вызывается функция</P>
      <P>unset($Webpage);</P>
      <P>Эта команда удаляет из памяти все содержимое $Webpage. Действуя в духе 
      инкапсуляции, можно поместить вызов unset( ) в метод с именем destroy( ) и 
      затем вызвать его:</P>
      <P>$Website-&gt;destroy( );</P>
      <P>Помните: необходимость в вызове деструкторов возникает лишь при работе 
      с объектами, использующими большой объем ресурсов, поскольку все 
      переменные и объекты автоматически уничтожаются по завершении 
сценария.</P>
      <P><A href="http.html://doks.gorodok.net/996" name=h></A>Простое и 
      иерархическое наследование</P>
      <P>Как говорилось выше, класс является шаблоном, по которому создаются 
      реальные объекты с определенными характеристиками и функциями. Нетрудно 
      представить себе ситуацию, при которой такой объект является частью 
      другого объекта. Например, автомобиль можно считать частным случаем 
      категории «транспортное средство», к которой относятся и самолеты. Хотя 
      разные типы транспортных средств сильно отличаются друг от друга, все они 
      характеризуются атрибутами из общего набора (количество колес, мощность, 
      максимальная скорость, модель и т. д.). Пусть конкретные значения этих 
      атрибутов сильно различаются — атрибуты все равно присущи всем 
      транспортным средствам. Таким образом, субклассы «автомобиль» и «самолет» 
      наследуют общий набор базовых характеристик от суперкласса «транспортное 
      средство». Концепция получения классом характеристик от другого, более 
      общего класса называется наследованием.</P>
      <P>Наследование является исключительно полезным средством 
      программирования, поскольку его применение предотвращает копирование кода, 
      совместно используемого структурами данных, — например, общих 
      характеристик различных типов транспортных средств, упоминавшихся в 
      предыдущем абзаце. В общем случае синтаксис наследования характеристик 
      другого класса в РНР выглядит так:</P>
      <P>class Class_name2 extends Class_name1 {</P>
      <P>объявления атрибутов;</P>
      <P>объявления методов;</P>
      <P>}</P>
      <P>Ключевое слово extends говорит о том, что класс Class_name2 наследует 
      все характеристики класса Class_name1.</P>
      <P>Помимо возможности многократного использования кода, наследование 
      обладает еще одним важным преимуществом — снижается вероятность ошибок 
      при</P>
      <P>модификации программы. Например, в иерархии, изображенной на рис. 6.1, 
      изменения в классе «автомобиль» никак не отразятся на коде (и данных) 
      класса «самолет», и наоборот.</P>
      <P>Вызов конструктора производного класса не приводит к автоматическому 
      вызову конструктора базового класса. </P>
      <P>Рис. 6.1. Иерархия транспортных средств</P>
      <P>В листинге 6.3 приведены классы, моделирующие иерархию, изображенную на 
      рис. 6.1.</P>
      <P>Листинг 6.3. Представление различных типов транспортных средств при 
      помощи наследования</P>
      <P>&lt;?</P>
      <P>// Транспортное средство&nbsp;</P>
      <P>class Vehicle {</P>
      <P>var $model;</P>
      <P>var $current_speed;</P>
      <P>function setSpeed($mph) {</P>
      <P>$this-&gt;current_speed = $mph;</P>
      <P>}</P>
      <P>function getSpeed() {</P>
      <P>return $this-&gt;current_speed;</P>
      <P>}</P>
      <P>}</P>
      <P>// Автомобиль</P>
      <P>class Auto extends Vehicle {&nbsp;</P>
      <P>var $fue1_type;</P>
      <P>function setFuelType($fuel) {</P>
      <P>$this-&gt;fuel_type = $fuel;</P>
      <P>}</P>
      <P>function getFuelType() {</P>
      <P>return $this-&gt;fuel_type;</P>
      <P>}</P>
      <P>}</P>
      <P>// Самолет</P>
      <P>class Airplane extends Vehicle {</P>
      <P>var $wingspan;</P>
      <P>function setWingSpan($wingspan) {</P>
      <P>$this-&gt;wingspan = $wingspan;</P>
      <P>}</P>
      <P>function getWingSpan() {</P>
      <P>return $this-&gt;wingspan;</P>
      <P>}</P>
      <P>}</P>
      <P>?&gt;</P>
      <P>Объекты этих классов создаются следующим образом:</P>
      <P>$tractor = new Vehicle;</P>
      <P>$gulfstream = new Airplane;</P>
      <P>Приведенные команды создают два объекта. Первый объект, $tractor, 
      относится к классу Vehicle. Второй объект, $gulfstream, относится к классу 
      Airplane и потому обладает как общими характеристиками класса Vehicle, так 
      и уточненными характеристиками класса Airplаne.</P>
      <P>Ситуация, при которой класс наследует свойства нескольких родительских 
      классов, называется множественным наследованием. К сожалению, в РНР 
      множественное наследование не поддерживается. Например, следующая 
      конструкция невозможна в РНР:</P>
      <P>class Airplane extends Vehicle extends Building...</P>
      <P>Многоуровневое наследование</P>
      <P>С увеличением размеров и сложности программ может возникнуть 
      необходимость в многоуровневом наследовании. Иначе говоря, класс будет 
      наследовать свои свойства от других классов, которые, в свою очередь, 
      будут наследовать от третьих классов и т. д. Многоуровневое наследование 
      развивает модульную структуру программы, обеспечивая простоту 
      сопровождения и более четкую логическую структуру. Скажем, при 
      использовании примера с транспортными средствами в большой программе может 
      появиться необходимость в дополнительном разбиении на субклассы 
      суперкласса Vehicle, продолжающем логическое развитие иерархии. Например, 
      транспортные средства можно дополнительно разделить на наземные, морские и 
      воздушные, чтобы суперкласс специализированных субклассов выбирался в 
      зависимости от среды, в которой перемещается данное транспортное средство. 
      Новый вариант иерархии показан на рис. 6.2.</P>
      <P>Краткий пример, приведенный в листинге 6.4, подчеркивает некоторые 
      важные аспекты многоуровневого наследования в РНР.</P>
      <P>Листинг 6.4. Многоуровневое наследование</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>Объявления атрибутов...</P>
      <P>Объявления методов...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>&nbsp; Объявления атрибутов...</P>
      <P>&nbsp; Объявления методов...</P>
      <P>}</P>
      <P>class Саr extends Land {</P>
      <P>&nbsp; Объявления атрибутов...</P>
      <P>&nbsp; Объявления методов...</P>
      <P>}</P>
      <P>$nissan = new Car;</P>
      <P>?&gt;</P>
      <P>Объект $nissan содержит все атрибуты и методы классов Саr, Land и 
      Vehicle. Как видите, программа получается исключительно модульной. 
      Допустим, когда-то в будущем вы захотите добавить в класс Land новый 
      атрибут. Нет проблем: внесите соответствующие изменения в класс Land, и 
      этот атрибут немедленно становится доступным для классов Land и Саr, не 
      влияя на функциональность других классов. Таким образом, модульность кода 
      и гибкость относятся к числу основных преимуществ ООП.</P>
      <P>Хотя масс наследует свои характеристики от цепочки родителей, 
      конструкторы родительских классов не вызываются автоматически при создании 
      объектов класса-наследника. Эти конструкторы могут вызываться 
      классом-наследником в виде методов.</P>
      <P><A name=i></A>Абстрактные классы</P>
      <P>В некоторых ситуациях бывает удобно создать класс, объекты которого 
      никогда не создаются (данный класс нужен всего лишь как базовый для 
      создания производных классов). Такие классы называются абстрактными. 
      Абстрактные классы обычно применяются в тех случаях, когда разработчик 
      программы хочет обеспечить обязательную поддержку некоторых функциональных 
      возможностей всеми классами, производными от абстрактного базового 
      класса.</P>
      <P>В РНР отсутствует прямая поддержка абстрактных классов, однако 
      существует простое обходное решение — достаточно определить в 
      «абстрактном» классе конструктор и включить в него вызов die( ). Вернемся 
      к классам из листинга 6.4. Скорее всего, вам никогда не придется создавать 
      экземпляры классов Land и Vehicle, поскольку они не могут представлять 
      физические объекты. Для представления реальных объектов (например, 
      автомобилей) следует создать класс, производный от этих классов. 
      Следовательно, чтобы предотвратить возможное создание объектов классов 
      Land и Vehicle, необходимо включить в их конструкторы вызовы die( ), как 
      показано в листинге 6.5.</P>
      <P>Листинг 6.5. Создание абстрактных классов</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>Объявления атрибутов...</P>
      <P>function Vehicle() }</P>
      <P>die ("Cannot create Abstract Vehicle class!");</P>
      <P>}</P>
      <P>Объявления других методов...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>Объявления атрибутов...</P>
      <P>function Land() }</P>
      <P>die ("Cannot create Abstract Land class!");</P>
      <P>}</P>
      <P>Объявления других методов. } class Car extends Land {</P>
      <P>Объявления атрибутов...</P>
      <P>Объявления методов...</P>
      <P>}</P>
      <P>?&gt;</P>
      <P>Попытка создания экземпляра этих абстрактных классов приведет к выдаче 
      сообщения об ошибке и завершению программы.</P>
      <P><A name=j></A>Перегрузка методов</P>
      <P>Перегрузкой методов называется определение нескольких методов с 
      одинаковыми именами, но разным количеством или типом параметров. Как и в 
      случае с абстрактными классами, в РНР эта возможность не поддерживается, 
      но существует простое обходное решение, приведенное в листинге 6.6.</P>
      <P>Листинг 6.6. Перегрузка методов</P>
      <P>&lt;?</P>
      <P>class Page {</P>
      <P>var $bgcolor;</P>
      <P>var $textcolor;</P>
      <P>&nbsp;function Page() {</P>
      <P>// Определить количество переданных аргументов</P>
      <P>// и вызвать метод с нужным именем</P>
      <P>$name = "Page".func_num_args();</P>
      <P>// Call $name with correct number of arguments passed in</P>
      <P>if ( func_num_args() == 0 ) :</P>
      <P>$this-&gt;$name();</P>
      <P>else :</P>
      <P>$this-&gt;$name(func_get_arg(0));</P>
      <P>endif;</P>
      <P>}</P>
      <P>function Page0() {</P>
      <P>$this-&gt;bgcolor = "white";</P>
      <P>$this-&gt;textcolor = "black";</P>
      <P>print "Created default page";</P>
      <P>}</P>
      <P>function Page1($bgcolor) {</P>
      <P>$this-&gt;bgcolor = $bgcolor;</P>
      <P>$this-&gt;textcolor = "black";</P>
      <P>print "Created custom page";</P>
      <P>}</P>
      <P>}</P>
      <P>$html_page - new Page("red");</P>
      <P>?&gt;</P>
      <P>В этом примере при создании нового объекта с именем $html_page 
      передается один аргумент. Поскольку в классе был определен конструктор по 
      умолчанию (Раgе( )), вызывается именно он. Однако конструктор по умолчанию 
      всего лишь выбирает, какому из конструкторов (Page0( ) или Page1( )) 
      следует передать управление. При выборе конструктора используются функции 
      func_num_args( ) и func_get_arg( ), которые, соответственно, определяют 
      количество аргументов и читают эти аргументы.</P>
      <P>Конечно, такое решение вряд ли можно назвать полноценной перегрузкой, 
      но оно подойдет для тех, кто не может жить без этого важного аспекта 
      ООП.</P>
      <P><A name=k></A>Функции для работы с классами и объектами</P>
      <P>В РНР существует несколько стандартных функций для работы с классами и 
      объектами; эти функции рассматриваются в следующих разделах. Все они часто 
      используются на практике, особенно в процессе разработки интерфейса, 
      администрирования кода и диагностики ошибок.</P>
      <P>get_class_methods( )</P>
      <P>Функция get_class_methods( ) возвращает массив имен методов класса с 
      заданным именем. Синтаксис функции get_class_methods( ):</P>
      <P>array get_class_methods (string имя_класса)</P>
      <P>Простой пример использования get_class_methods( ) приведен в листинге 
      6.7.</P>
      <P>Листинг 6.7. Получение списка методов класса</P>
      <P>&lt;?</P>
      <P>...</P>
      <P>class Airplane extends Vehicle {&nbsp;</P>
      <P>var $wingspan;</P>
      <P>function setWingSpan($wingspan) {&nbsp;</P>
      <P>$this-&gt;wingspan = $wingspan;</P>
      <P>}</P>
      <P>function getWingSpan() {&nbsp;</P>
      <P>return $this-&gt;wingspan;</P>
      <P>}</P>
      <P>}</P>
      <P>$cls_methods = get_class_methods(Airplane);</P>
      <P>// Массив $cls_methods содержит имена всех методов,</P>
      <P>// объявленных в классах "Airplane" и "Vehicle"</P>
      <P>?&gt;</P>
      <P>Как видно из листинга 6.7, функция get_class_methods( ) позволяет легко 
      получить информацию обо всех методах, поддерживаемых классом.</P>
      <P>get_class_vars( )</P>
      <P>Функция get_class_vars( ) возвращает массив имен атрибутов класса с 
      заданным именем. Синтаксис функции get_class_vars( ):</P>
      <P>array get_class_vars (string имя_класса)</P>
      <P>Пример использования get_class_vars( ) приведен в листинге 6.8.</P>
      <P>Листинг 6.8. Получение списка атрибутов класса функцией get_class_vars( 
      )</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>var $model;</P>
      <P>var $current_speed; }</P>
      <P>class Airplane extends Vehicle {</P>
      <P>var Swingspan; } $a_class = "Airplane";</P>
      <P>$attribs = get_class_vars($a_class);</P>
      <P>// $attribs = array ( "wingspan", "model", "current_speed")</P>
      <P>?&gt;</P>
      <P>Массив $attribs заполняется именами всех атрибутов класса Airplane.</P>
      <P>get_object_vars( )</P>
      <P>Функция get_object_vars( ) возвращает ассоциативный массив с 
      информацией обо всех атрибутах объекта с заданным именем. Синтаксис 
      функции get_object_vars( ):</P>
      <P>array get_object_vars (object имя_обьекта)</P>
      <P>Пример использования функции get_object_vars( ) приведен в листинге 
      6.9.</P>
      <P>Листинг 6.9. Получение информации о переменных объекта&nbsp; </P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>var Swheels;</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>var Sengine;</P>
      <P>}</P>
      <P>class car extends Land {</P>
      <P>var $doors:</P>
      <P>function car($doors, $eng, $wheels) {</P>
      <P>$this-&gt;doors = $doors;</P>
      <P>$this-&gt;engine = $eng;</P>
      <P>$this-&gt;wheels = $wheels;</P>
      <P>}</P>
      <P>function get_wheels() {</P>
      <P>return $this-&gt;wheels;</P>
      <P>}</P>
      <P>}</P>
      <P>$toyota = new car(2,400,4);</P>
      <P>$vars = get_object_vars($toyota);</P>
      <P>while (list($key, $value) = each($vars)) :</P>
      <P>print "$key ==&gt; $value &lt;br&gt;";</P>
      <P>endwhile;</P>
      <P>// Выходные данные:</P>
      <P>// doors ==&gt; 2</P>
      <P>// engine ==&gt; 400</P>
      <P>// wheels ==&gt; 2</P>
      <P>?&gt;</P>
      <P>Функция get_object_vars( ) позволяет быстро получить всю информацию об 
      атрибутах конкретного объекта и их значениях в виде ассоциативного 
      массива.</P>
      <P>method_exists( )</P>
      <P>Функция method_exists( ) проверяет, поддерживается ли объектом метод с 
      заданным именем. Если метод поддерживается, функция возвращает TRUE, в 
      противном случае возвращается FALSE. Синтаксис функции method_exists( 
      ):</P>
      <P>bool method_exi sts (object имя_обьекта. string имя_метода)</P>
      <P>Пример использования метода method_exists( ) приведён в листинге 
      6.10.</P>
      <P>Листинг 6.10. Проверка поддержки метода объектом при помощи функции 
      method_exists()</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>var $fourWheel;</P>
      <P>function setFourWheel Drive() {</P>
      <P>$this-&gt;fourWeel = 1;</P>
      <P>}</P>
      <P>}</P>
      <P>// Создать объект с именем $саr</P>
      <P>$car = new Land;</P>
      <P>// Если метод "fourWheelDrive" поддерживается классом "Land"</P>
      <P>// или "Vehicle", вызов method_exists возвращает TRUE;</P>
      <P>// в противном случае возвращается FALSE.</P>
      <P>// В данном примере method_exists() возвращает TRUE.</P>
      <P>if (method_exists($car, "setfourWheelDrive")) :</P>
      <P>print "This car is equipped with 4-wheel drive";</P>
      <P>else :</P>
      <P>print "This car is not equipped with 4-wheel drive";</P>
      <P>endif;</P>
      <P>?&gt;</P>
      <P>В листинге 6.10 функция method_exists ( ) проверяет, поддерживается ли 
      объектом $car метод с именем setFourWheelDrive( ). Если метод 
      поддерживается, функция возвращает логическую истину и фрагмент выводит 
      соответствующее сообщение. В противном случае возвращается FALSE и 
      выводится другое сообщение.</P>
      <P>get_class( )</P>
      <P>Функция get_class( ) возвращает имя класса, к которому относится объект 
      с заданным именем. Синтаксис функции get_class( ): </P>
      <P>string get_class(object имя_объекта);</P>
      <P>Пример использования get_class( ) приведен в листинге 6.11.</P>
      <P>Листинг 6.11. Получение имени класса функцией get_class( )</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>...</P>
      <P>class Land extends Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>// Создать объект с именем $саr $car = new Land;</P>
      <P>// Переменной $class_a присваивается строка "Land"</P>
      <P>$class_a = get_class($car);</P>
      <P>?&gt;</P>
      <P>В результате переменной $class_a присваивается имя класса, на основе 
      которого был создан объект $саr.</P>
      <P>get_parent_class( )</P>
      <P>Функция get_parent_class( ) возвращает имя родительского класса (если 
      он есть) для объекта с заданным именем. Синтаксис функции get_parent_dass( 
      ):</P>
      <P>string get_parent_class (object имя_обьекта);</P>
      <P>Листинг 6.12 демонстрирует использование get_parent_class( ).</P>
      <P>Листинг 6.12. Получение имени родительского класса функцией 
      get_parent_class( )</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>// Создать объект с именем $саr $саr = new Land;</P>
      <P>// Переменной $parent присваивается строка "Vehicle"</P>
      <P>$parent = get_parent_dass($car);</P>
      <P>?&gt;</P>
      <P>Как и следовало ожидать, при вызове get_parent_class( ) переменной 
      $parent будет присвоена строка "Vehicle".</P>
      <P>is_subclass_of( )</P>
      <P>Функция is_subclass_of( ) проверяет, был ли объект создан на базе 
      класса, имеющего родительский класс с заданным именем. Функция возвращает 
      TRUE, если проверка дает положительный результат, и FALSE в противном 
      случае. Синтаксис функции is_subclass_of( ):</P>
      <P>bool is_subclass_of (object объект, string имя_класса)</P>
      <P>Использование is_subclass_of( ) продемонстрировано в листинге 6.13.</P>
      <P>Листинг 6.13. Использование функции is_subdass_of( )</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>$auto = new Land;</P>
      <P>// Переменной $is_subclass присваивается TRUE</P>
      <P>$is_subclass = is_subclass_of($auto, "Vehicle");</P>
      <P>?&gt;</P>
      <P>В листинге 6.13 переменной $is_subclass( ) присваивается признак того, 
      принадлежит ли объект $auto к субклассу родительского класса Vehicle. В 
      приведенном фрагменте $auto относится к классу Vehicle; следовательно, 
      переменной $is_subclass( ) будет присвоено значение TRUE.</P>
      <P>get_declared_classes( )</P>
      <P>Функция get_declared_classes( ) возвращает массив с именами всех 
      определенных классов (листинг 6.14). Синтаксис функции 
      get_declared_classes( ):</P>
      <P>array get_declared_classes( )</P>
      <P>Листинг 6.14. Получение списка классов функцией get_declared_classes( 
      )</P>
      <P>&lt;?</P>
      <P>class Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>class Land extends Vehicle {</P>
      <P>...</P>
      <P>}</P>
      <P>$declared_classes = get_declared_classes();</P>
      <P>// $declared_classes = array("Vehicle", "Land")</P>
      <P>?&gt;</P>
      <P><A name=l></A>Итоги</P>
      <P>В этой главе были представлены некоторые концепции 
      объектно-ориентированного программирования, при этом особое внимание 
      уделялось их реализации в языке РНР. В частности, были рассмотрены 
      следующие темы:</P>
      <UL>
        <LI>общие принципы объектно-ориентированного программирования; 
        <LI>классы, объекты и методы; 
        <LI>простое и иерархическое наследование; 
        <LI>абстрактные классы; 
        <LI>перегрузка методов; 
        <LI>функции для работы с классами и объектами в РНР. </LI></UL>
      <P>Технология объектно-ориентированного программирования не очень сложна, 
      но полное усвоение всех концепций обычно требует некоторого времени. 
      Однако я гарантирую, что затраченное время полностью окупится — ООП 
      поднимет эффективность вашей работы на принципиально новый 
      уровень.</P></LI></DIV>
<center>
[ <a href="05.php">Назад</a> | <a href="index.php">Содержание</a> | <a href="07.php">Вперед</a> ]
</center><br>
<? include_once '../../sys/inc/tfoot.php'; ?>