PHP — Наследование
При наследовании дочерний класс получает все публичные и защищённые свойства и методы родительского класса и может добавлять собственные свойства и методы.
Примечание: Дочерний класс не имеет доступа к приватным методам родителя.
Чтобы создать унаследованный класс, используйте ключевое слово extends.
В следующем примере Strawberry расширяет Fruit. Благодаря наследованию он может использовать публичные свойства $name и $color и публичные методы __construct() и intro() из Fruit. Кроме них, Strawberry определяет ещё один собственный метод, message().
Пример
Strawberry получает всё публичное из Fruit и добавляет message():
Вывод: PHP-скрипт
<?php
// Родительский класс
class Fruit {
public $name;
public $color;
public function __construct($name, $color) {
$this->name = $name;
$this->color = $color;
}
public function intro() {
echo "Этот фрукт — $this->name, а его цвет — $this->color.<br>";
}
}
// Strawberry наследуется от Fruit
class Strawberry extends Fruit {
public function message() {
echo "Я фрукт или ягода? ";
}
}
$strawberry = new Strawberry("Strawberry", "red");
$strawberry->intro();
$strawberry->message();
?>
PHP — Наследование и модификатор доступа protected
В предыдущей главе было показано, что члены с модификатором protected доступны самому классу и производным от него классам.
С внешним кодом всё иначе: вызов оттуда метода protected заканчивается ошибкой, а методы public продолжают работать как обычно.
Пример
Здесь внешний код вызывает protected-метод intro() и получает ошибку:
Вывод: PHP-скрипт
<?php
class Fruit {
public $name;
public $color;
public function __construct($name, $color) {
$this->name = $name;
$this->color = $color;
}
protected function intro() {
echo "Этот фрукт — $this->name, а его цвет — $this->color.";
}
}
class Strawberry extends Fruit {
public function message() {
echo "Я фрукт или ягода? ";
}
}
// Пробуем вызвать все три метода извне класса
$strawberry = new Strawberry("Strawberry", "red"); // OK. __construct() — публичный
$strawberry->message(); // OK. message() — публичный
$strawberry->intro(); // ОШИБКА. intro() — защищённый
?>
Пример
Производный класс может без проблем вызвать тот же protected-метод изнутри:
Вывод: PHP-скрипт
<?php
class Fruit {
public $name;
public $color;
public function __construct($name, $color) {
$this->name = $name;
$this->color = $color;
}
protected function intro() {
echo "Этот фрукт — $this->name, а его цвет — $this->color.";
}
}
class Strawberry extends Fruit {
public function message() {
echo "Я фрукт или ягода? ";
// Вызов защищённого метода изнутри производного класса — OK
$this -> intro();
}
}
$strawberry = new Strawberry("Strawberry", "red"); // OK. __construct() — публичный
$strawberry->message(); // OK. message() — публичный и вызывает intro() (который защищён) изнутри производного класса
?>
PHP — Переопределение унаследованных методов
Дочерний класс может заменить унаследованный метод. Для этого достаточно определить в дочернем классе метод с тем же именем; это называется переопределением.
В следующем примере Strawberry (дочерний класс) предоставляет собственные __construct() и intro(), и они переопределяют версии из Fruit (родительского класса):
Пример
Выполняются именно те версии __construct() и intro(), которые находятся в Strawberry:
Вывод: PHP-скрипт
<?php
class Fruit {
public $name;
public $color;
public function __construct($name, $color) {
$this->name = $name;
$this->color = $color;
}
public function intro() {
echo "Этот фрукт — $this->name, а его цвет — $this->color.";
}
}
class Strawberry extends Fruit {
public $weight;
public function __construct($name, $color, $weight) {
$this->name = $name;
$this->color = $color;
$this->weight = $weight;
}
public function intro() {
echo "$this->name имеет цвет $this->color, а вес — $this->weight грамм.";
}
}
$strawberry = new Strawberry("Strawberry", "red", 50);
$strawberry->intro();
?>
PHP — Ключевое слово final
Иногда класс или метод должен оставаться именно таким, каким написан. Для этого есть ключевое слово final: для класса оно запрещает наследование, а для метода — переопределение.
Пример
Класс с пометкой final нельзя расширить, поэтому этот код завершается фатальной ошибкой:
Вывод: PHP-скрипт
<?php
final class Fruit {
// какой-то код
}
// приведёт к ошибке
class Strawberry extends Fruit {
// какой-то код
}
?>
Пример
Метод с пометкой final нельзя переопределить в дочернем классе, поэтому этот код тоже завершается фатальной ошибкой:
Вывод: PHP-скрипт
<?php
class Fruit {
final public function intro() {
// какой-то код
}
}
class Strawberry extends Fruit {
// приведёт к ошибке
public function intro() {
// какой-то код
}
}
?>