Наследование
Наследование позволяет создать новый класс на основе существующего. Новый класс получает все свойства и методы родителя и может добавить свои или изменить унаследованные.
extends
Класс-наследник объявляют словом extends:
<?php
class Animal
{
public function __construct(protected string $name) {}
public function describe(): string
{
return "{$this->name} — животное";
}
}
class Dog extends Animal
{
public function bark(): string
{
return "{$this->name}: Гав!";
}
}
$dog = new Dog('Шарик');
echo $dog->describe(), "\n"; // Шарик — животное
echo $dog->bark(); // Шарик: Гав!У Dog нет своего конструктора и метода describe() — они достались от Animal.
protected
Модификатор protected — промежуточный между public и private: свойство недоступно снаружи, но доступно в самом классе и в его наследниках. Если бы $name было private, метод bark() не смог бы его прочитать.
Переопределение методов
Наследник может объявить метод с тем же именем — тогда будет вызываться его версия. Вызвать родительскую версию позволяет parent:::
<?php
class Cat
{
public function sound(): string
{
return 'Мяу';
}
}
class Kitten extends Cat
{
public function sound(): string
{
return parent::sound() . '-мяу';
}
}
echo (new Kitten())->sound(); // Мяу-мяуПолиморфизм
Код может работать с объектами разных классов одинаково, если у них есть общий метод. Какая версия метода выполнится, зависит от самого объекта:
<?php
class Animal
{
public function sound(): string
{
return '...';
}
}
class Cat extends Animal
{
public function sound(): string
{
return 'Мяу';
}
}
class Dog extends Animal
{
public function sound(): string
{
return 'Гав';
}
}
foreach ([new Cat(), new Dog(), new Animal()] as $animal) {
echo $animal->sound(), "\n";
}Циклу не нужно знать, кошка перед ним или собака.
Проверка типа
Оператор instanceof проверяет, принадлежит ли объект классу. Объект наследника считается и объектом родителя:
<?php
class Animal {}
class Dog extends Animal {}
$dog = new Dog();
var_dump($dog instanceof Dog); // bool(true)
var_dump($dog instanceof Animal); // bool(true)Частая ошибка
Наследование стоит применять, только когда наследник действительно является разновидностью родителя: собака — это животное. Наследовать класс лишь ради того, чтобы взять из него пару методов, не нужно — это запутывает программу.