Наследование
Ключевое слово extends говорит о том, что создаваемый класс является лишь "расширением" класса A, и не более того. То есть B содержит те же самые свойства и методы, что и A, но, помимо них и еще некоторые дополнительные, "свои".
Теперь "часть A" находится прямо внутри класса B и может быть легко доступна, наравне с методами и свойствами самого класса B. Например, для объекта $obj класса B допустимы выражения $obj->TestA() и $obj->TestB().
Итак, мы видим, что, действительно, класс B является воплощением идеи "расширение функциональности
класса A". Обратите также внимание: мы можем теперь забыть, что B унаследовал от A некоторые свойства или методы — снаружи все выглядит так, будто класс B реализует их самостоятельно.
Немного о терминологии: родительский класс A принято называть базовым классом, а класс дочерний классB — производным от A. Иногда базовый класс также называют суперклассом, а производный — подкласcом.
Рассмотрим еще один пример на PHP:
<?php
class Parent {
function parent_funct() { echo "<h1>Это родительская функция</h1>"; }
function test () { echo "<h1>Это родительский класс</h1>"; }
}
class Child extends Parent {
function child_funct() { echo "<h2>Это дочерняя функция</h2>"; }
function test () { echo "<h2>Это дочерний класс</h2>"; }
}
$object = new Parent;
$object = new Child;
$object->parent_funct(); // Выводит 'Это родительская функция'
$object->child_funct(); // Выводит 'Это дочерняя функция'
$object->test(); // Выводит 'Это дочерний класс'
?>
Дочерний класс (подкласс) Child наследует все методы и свойства суперкласса Parent.
Конструкторы в классах-родителях не вызываются автоматически. Чтобы вызвать конструктор, объявленный в родительском классе, следует обратиться к методу parent::__construct().
<?php
class BaseClass {
function __construct() {
print "Конструктор класса BaseClass\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "Конструктор класса SubClass\n";
}
}
$obj = new BaseClass();
$obj = new SubClass();
?>
Как и в случае с конструкторами, деструкторы, объявленные в родительском классе, не будут вызваны автоматически. Для вызова деструктора, объявленном в классе-родителе, следует обратиться к методу parent::__destruct().
Полиморфизм (многоформенность) является следствием идеи наследования. В общих словах, полиморфность класса — это свойство базового класса использовать функции производных классов, даже если на момент определения еще неизвестно, какой именно класс будет включать его в качестве базового и, тем самым, становиться от него производным.
Рассмотрим свойство полиморфности классов на основе следующего примера:
<?php
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() — фигура сама "решит", какого она типа и как ее рисовать.
А вот еще один практический пример, показывающий свойство класса - полиморфизм:
<?php
class Base {
function funct() {
echo "<h2>Функция базового класса</h2>";
}
function base_funct() {
$this->funct();
}
}
class Derivative extends Base {
function funct() {
echo "<h3>Функция производного класса</h3>";
}
}
$b = new Base();
$d = new Derivative();
$b->base_funct();
$d->funct();
$d->base_funct();
// Скрипт выводит:
// Функция базового класса
// Функция производного класса
// Функция производного класса
?>
В рассмотренном примере функция base_funct() класса Base была перезаписана одноименной функцией класса Derivative.
Т.е. чтобы изменить поведение существующих свойств или методов в новом классе, вы можете просто перегрузить их с помощью повторного объявления в новом классе:
Обращение к элементам классов в PHP5 (::)
Используя эту оператор :: можно обращаться к константам, статическим или перегруженным свойствам или методам класса.
При обращении к этим элементам извне класса, программист должен использовать имя этого класса.
Обозначение "двойное двоеточие" (::) не менялось ни разу в течение всего времени разработки PHP.
Использование :: вне объявления класса
<?php
class MyClass {
const CONST_VALUE = 'Значение константы';
}
echo MyClass::CONST_VALUE;
?>
Использование :: в объявлении класса
Для обращения к свойствам и методам в объявлении класса используются ключевые слова self и parent. Пример использования :: в объявлении класса:
<?php
class OtherClass extends MyClass {
public static $my_static = 'статическая переменная';
public static function doubleColon() {
echo parent::CONST_VALUE . "\n";
echo self::$my_static . "\n";
}
}
OtherClass::doubleColon();
?>
Когда дочерний класс перегружает методы, объявленные в классе-родителе, PHP не будет осуществлять автоматический вызов методов, принадлежащих классу-родителю. Этот функционал возлагается на метод, перегружаемый в дочернем классе. Данное правило распространяется на конструкторы и деструкторы, перегруженные и другие методы.
Обращение к методу в родительском классе
<?php
class MyClass {
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass {
/* Override parent's definition */
public function myFunc() {
/* But still call the parent function */
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}
$class = new OtherClass();
$class->myFunc();
?>
Все специфические возможности, которыми обладает оператор :: в PHP5, не являются доступными в более ранних версиях PHP.