ООП. Наследование классов в php
![]() |
Классы в php версии 5 могут наследоваться, т.е. приобретать свойства и методы своего родителя. А зачем вообще нужно наследование классов? |
Рассмотрим наследование на примере человека. Я – человек. И я наследую некоторые свойства класса Человек, например возможность говорить, интеллект, необходимость в воздухе, воде, пище и всяких витаминах. Эти свойства не уникальны для каждого отдельного человека, т.е. всем людям присуще то, что я перечислил. Мы еще можем заметить, что класс Человек наследует зависимость от воды, воздуха и пищи у класса Млекопитающие. А этот класс наследует эти свойства у класса Животные.
Благодаря наследованию мы можем очень много сэкономить на описании реального объекта. Например, спросите меня – что такое утка? Я отвечу: это птица, которая крякает. Я вроде бы сказал всего 4 слова, но полностью в этих четырех словах уместилась вся необходимая информация для описания утки, потому что сказав «птица, которая крякает», я дал вам знать, что утке присущи все свойства птицы плюс свойство «кряканье»
Наследуем
Короче тем самым объектно-ориентированные языки позволяют создавать модели, очень близкие к реальному миру. Для примера студентов и аспирантов мы можем сказать, что аспирант – это не простой студент. Он обладает дополнительными свойствами, но одновременно он обладает и всеми свойствами студента. Поэтому мы можем унаследовать класс GraduateStudent (аспирант) от класса Student (студент) с помощью ключевого слова extends:
class Student {
}
class GraduateStudent extends Student {
}
?>
Тут класс Student будет называться базовым, а класс GraduateStudent – производным.
Наследование еще позволяет нам избавиться от повторения кода, потому что все открытые (public, protected) методы и свойства класса Student становятся доступными и в классе GraduateStudent. Помните, в статье ранее я говорил, что модификаторы доступа методов/свойств private и protected отличаются? Вот. Если у нас есть свойство (или метод) private в классе Student, то оно не будет доступно в классе GraduateStudent:
class Student {
private $mark;
protected $average;
}
class GraduateStudent extends Student {
function someFn() {
$this->mark = 5; // Ошибка доступа!
$this->average = 4.4; // А так правильно
}
}
?>
Кстати. Помните, что если свойство или метод в классе не имеют модификатора доступа, то по умолчанию они public? Видимо это было введено для совместимости с предыдущими версиями пхп, где модификаторов еще не было, а все члены класса были публичными.
Вспомним еще конструкторы и деструкторы. Так вот, если нам надо вызвать конструктор или деструктор базового класса, то надо это делать явно, через указатель parent:
class MyClass {
function __construct() {
echo "Запущен конструктор базового класса";
}
function __destruct() {
echo "Запущен деструктор базового класса";
}
}
class MyClass1 extends MyClass {
function __construct() {
parent::__construct();
}
function __destruct() {
parent::__destruct();
}
}
$obj = new MyClass1(); // Выводит "Запущен конструктор базового класса"
unset($obj); // Выводит "Запущен деструктор базового класса"
?>
Сейчас это может показаться лишним, но в реальной практике это зачастую очень нужно. Я знаю это по собственному опыту написания программ на C#.
Абстрактные классы и методы
Это тоже новинка в PHP5. Абстрактные методы имеют только объявление и не имеют реализации. Класс, который содержит такие методы, должен быть обязательно объявлен как абстрактный:
abstract class MyClass {
abstract public function fn();
}
?>
Т.е. если бы мы написали так…
abstract class MyClass {
abstract public function fn() {
}
}
?>
…интерпретатор пхп заругался бы на нас.
Абстрактные классы могут еще содержать и обычные (не абстрактные) элементы. Создать объект абстрактного класса мы не имеем права. Можно только определять новые классы от базового абстрактного класса и создавать объекты уже от производных классов.
А зачем тогда нужны абстрактные методы и классы? А чтобы описать объект, который будет реализован, но который еще не реализован.
А здесь я приведу пример, как использовать абстрактный метод базового класса в производном классе:
abstract class MyClass {
abstract public function fn();
}
class MyClass1 extends MyClass {
public function fn() {
echo “привет”;
}
}
$obj = new MyClass1;
$obj->fn(); // Выводит “привет”
?>
Интерфейсы
В моем понимании интерфейс – нечто, с помощью чего мы можем управлять объектом. Например, возьмем телевизор. У него есть интерфейс – панель с кнопками спереди под экраном или справа (слева) от экрана. Ну пульт управления – это тоже интерфейс. Т.е. большинство из нас не знает, как сделан телевизор и как он работает, но мы знаем, как им можно управлять (переключать каналы, настраивать громкость, яркость и т.д.). То же самое было придумано и в программировании.
С точки зрения программиста, интерфейс (interface) – это абстрактный класс, который содержит только абстрактные методы и не имеет никаких свойств.
Основное отличие интерфейсов от абстрактных классов – в том, что в PHP 5 класс не может быть порожден от нескольких классов (и абстрактных в т.ч.), но зато может быть создан на основе любого числа интерфейсов. При этом в интерфейсе методы должны объявляться ключевым словом function без указания всяких спецификаторов (в т.ч. и abstract):
interface Inter1 {
function fn1();
}
interface Inter2 {
function fn2();
}
class MyClass implements Inter1, Inter2 {
public function fn1() {
echo 1;
}
public function fn2() {
echo 2;
}
}
$obj = new MyClass;
$obj->fn1(); // Выведет 1
$obj->fn2(); // Выведет 2
?>
Также в ООП есть такое понятие, как множественное наследование. Суть его в том, что один и тот же класс может иметь несколько базовых классов. Но для PHP5 это не совсем справедливо. В PHP5 класс не может быть унаследован от нескольких базовых классов, но зато может реализовать сколько угодно интерфейсов, как показано в последнем примере.
Финальные методы и классы
Интересная возможность в пхп 5, на которую я наткнулся в ходе изучения ООП, – это возможность определять финальные методы и классы.
Метод, который мы определили с ключевым словом final, в дальнейшем мы не можем переопределить в классах, которые производны от нашего класса:
class MyClass {
final public function fn() {
// Код метода
}
}
class MyClass1 extends MyClass {
// Следующий код вызывает ошибку
// переопределения финального метода
// базового класса MyClass
public function fn() {
// Код метода
}
}
?>
И еще: если мы используем final при определении самого класса, то не сможем больше породить от него другие классы:
final class MyClass {
// Код описания класса
}
// Следующий код вызывает ошибку
// порождения от финального класса
class MyClass1 extends MyClass {
// Код описания класса
}
?>
Тут заметим, что если класс определен как final, то и все методы этого класса автоматически станут финальными, и определять их явно как final уже не надо.
А как насчет свойств? Свойства класса определять финальными нельзя. Ну в этом не было бы смысла, думаю. Потому что, в отличие от методов, мы не можем переопределять свойства класса. Мы можем их только наследовать.
Выводы
На этом я почти заканчиваю рассмотрение объектно-ориентированного программирования в PHP5. Осталась только одна очень важная вещь – это полиморфизм. Но о ней я вскоре расскажу в другой статье. Надеюсь, я доступно объяснил то, что сам недавно изучил

Июль 14th, 2008
Вы забыли удалить слово abstract при корпировании кода (там, где “Т.е. если бы мы написали так…”)
Июль 14th, 2008
Нет, я там ничего не забыл. Смысл написанного “Т.е. если бы мы написали так…” был в том, чтобы показать, что абстрактный метод не имеет тела. Там мной приведено два примера: первый – без тела, второй – с телом. Просто этого не заметно с первого взгляда.
Март 12th, 2009
сп, статья порадовала, лаконична:).
Июль 8th, 2009
ага, объяснили все доступно, спасибо, но самое главное лаконично, после прочтения последней строчки, мог не успел взорваться ))
Декабрь 9th, 2009
Статья хорошо написана. молодец
Декабрь 15th, 2009
Скажите, из-за чего может дочерний класс не наследовать переменные?
у меня именно так и происходит, хотя даже ошибок нет и не выдает:(
Апрель 14th, 2010
думаю из-за того что они объявлены как private-переменные)) я новичок)) так что прошу сильно не ругать))
Апрель 29th, 2010
Классная статья, еще можно добавить про статичные методы и св-ва
Июнь 16th, 2010
Спасибо, статья очень помогла!