| |
... }
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 таких возможностей нет.
Полиморфизм
Полиморфизм (многоформенность) — это, я бы сказал, одно из интересных следст-
вий идеи наследования. В общих словах, полиморфность класса — это его способ-
ность использовать функции производных от него классов, даже если на момент оп-
ределения еще неизвестно, какой именно класс будет включать его в качестве
базового и, тем самым, становиться от него производным.
Часть V. Приемы программирования на PHP 464
Вернемся к нашему предыдущему примеру с классами A и B.
class A {
// Выводит, функция какого класса была вызвана
function Test() { echo "Test from A\n"; }
// Тестовая функция — просто переадресует на Test()
function Call() { Test(); }
}
class B extends A {
// Функция Test() для класса B
function Test() { echo "Test from B\n"; }
}
$a=new A();
$b=new B();
Давайте рассмотрим следующие команды:
$a->Call(); // напечатается "Test from A"
$b->Test(); // напечатается "Test from B"
$b->Call(); // Внимание! Напечатается "Test from B"!
Обратите внимание на последнюю строчку: вопреки ожиданиям, вызывается не
функция Test() из класса A, а функция из класса B! Складывается впечатление,
что
Test() из B просто переопределила функцию Test() из A. Так оно на самом деле и
есть. Функция, переопределяемая в производном классе, называется виртуальной.
Механизм виртуальных функций позволяет нам, например, "подсовывать" функциям,
ожидающим объект одного класса, объект другого, производного, класса. Еще один
классический пример — класс, воплощающий собой свойства геометрической фигу-
ры, и несколько производных от него классов — квадрат, круг, треугольник и т. д.
Базовый класс имеет виртуальную функцию Draw(), которая заставляет объект нари-
совать самого себя. Все производные классы-фигуры, разумеется, переопределяют
эту
функцию (ведь каждую фигуру нужно рисовать по-особому). Также у нас есть массив
фигур, причем мы не знаем, каких именно. Зато, используя полиморфизм, мы можем,
не задумываясь, перебрать все элементы массива и вызвать для каждого из них
метод
Draw() — фигура сама "решит", какого она типа и как ее рисовать.
В нашем классе MysqlTable, который мы еще только-только наметили, идея
|
|