Наследование
Создание самодостаточных объектов — довольно неплохая идея. Однако это далеко не единственная возможность ООП. Сейчас мы займемся наследованием — одним из основных понятий ООП.
Итак, пусть у нас есть некоторый класс A с определенными свойствами и методами. Но то, что этот класс делает, нас не совсем устраивает — например, пусть он выполняет большинство функций, по сути нам необходимых, но не реализует некоторых других. Зададимся целью создать новый класс B, как бы "расширяющий"
возможности класса A, добавляющий ему несколько новых свойств и методов. Сделать это можно двумя принципиально различными способами. Первый выглядит примерно так:
class A {
function TestA() { ... }
function Test() { ... }
}
class B {
var $a; // объект класса A
function B(параметры_для_A, другие_параметры)
{ $a=new A(параметры_для_A);
инициализируем другие поля B
}
function TestB() { ... }
function Test() { ... }
}
Поясню: в этой реализации объект класса B содержит в своем составе подобъект класса A в качестве свойства. Это свойство — лишь "частичка" объекта класса B, не более того. Подобъект не "знает", что он в действительности не самостоятелен, а содержится в классе B, поэтому не может предпринимать никаких действий, специфичных для этого класса.
Но вспомним, что мы хотели получить расширение
возможностей класса A, а не нечто, содержащее объекты A. Что означает "расширение"? Лишь одно: мы бы хотели, чтобы везде, где допустима работа с объектами класса A, была допустима и работа с объектами класса B. Но в нашем примере это совсем не так.
r Мы не видим явно, что класс B лишь расширяет возможности A, а не является отдельной сущностью.
r Мы должны обращаться к "части A" класса B через $obj->a->TestA(), а к членам самого класса B как $obj->TestB(). Последнее может быть довольно утомительным, если, как это часто бывает, в B будет использоваться очень много методов из A и гораздо меньше — из B. Кроме того, это заставляет нас постоянно помнить о внутреннем устройстве класса B.
Впрочем, такой способ расширения также иногда находит применение. Мы поговорим об этом чуть позже. А пока рассмотрим, что же представляет собой наследование
(или расширение возможностей) классов.
class B extends A {
function B(параметры_для_A, другие_параметры)
{ $this->A(параметры_для_A);
инициализируем другие поля B
}
function TestB() { ... }
function Test() { ... }
}
Ключевое слово extends говорит о том, что создаваемый класс является лишь "расширением"
класса A, и не более того. То есть B содержит те же самые свойства и методы, что и A, но, помимо них и еще некоторые дополнительные, "свои".
Теперь "часть A" находится прямо внутри класса B
и может быть легко доступна, наравне с методами и свойствами самого класса B. Например, для объекта $obj класса B допустимы выражения $obj->TestA()
и $obj->TestB(). Итак, мы видим, что, действительно, класс B
является воплощением идеи "расширение функциональности класса A". Обратите также внимание: мы можем теперь забыть, что B
унаследовал от A
некоторые свойства или методы — снаружи все выглядит так, будто класс B реализует их самостоятельно.
Немного о терминологии: принято класс A называть базовым, а класс B — производным от A. Иногда базовый класс также называют суперклассом, а производный — подкласcом.
Зачем может понадобиться наследование? Например, мы написали класс Mysql-таблицы и хотели бы дополнительно иметь класс Guestbook (гостевая книга). Очевидно, в классе Guestbook будет много методов, которые нужны для того же, что и методы из MysqlTable, поэтому было бы разумным сделать его производным от MysqlTable:
class Guestbook extends MysqlTable {
. . .
методы и свойства, которых нет в MysqlTable
и которые относятся к гостевой книге
}
Многие языки программирования поддерживают множественное наследование (то есть такое, когда, скажем, класс B наследует члены не одного, а сразу нескольких классов — например, A и Z). К сожалению, в PHP таких возможностей нет.