Наследование в PHP (2ч)

Оператор instanceof

Когда у вас несколько классов в одной иерархии, возникает вопрос: как во время выполнения программы узнать, к какому именно типу принадлежит объект? Для этого существует оператор instanceof. Он возвращает true, если объект является экземпляром указанного класса или любого его потомка.

Важный нюанс: instanceof учитывает всю цепочку. Объект дочернего класса одновременно является экземпляром родительского — это называется принципом подстановки Лисков.

$email  = new EmailNotification('a@b.ru', 'Привет');

$urgent = new UrgentNotification('a@b.ru', 'Срочно!');

var_dump($email  instanceof EmailNotification); // true

var_dump($email  instanceof Notification);      // true — это тоже Notification

var_dump($urgent instanceof EmailNotification); // false — другая ветка

 

// Практическое применение: разная обработка по типу

function dispatch(Notification $n): void

{

    if ($n instanceof UrgentNotification) {

        echo "Немедленно отправляем: " . $n->format() . "\n";

        return;

    }

    echo "Стандартная очередь: " . $n->format() . "\n";

}

 

dispatch($email);  // Стандартная очередь: [a@b.ru] Привет

dispatch($urgent); // Немедленно отправляем: [СРОЧНО] Срочно!

instanceof работает не только с классами, но и с интерфейсами. Если объект реализует интерфейс, проверка $obj instanceof SomeInterface вернёт true. Это делает оператор универсальным инструментом для проверки типов.

 

Запрет наследования: оператор final

Иногда нужно защитить класс или отдельный метод от переопределения. PHP предоставляет для этого ключевое слово final. Оно применяется в двух сценариях.

final перед классом

Класс, объявленный как final, не может иметь потомков вообще. Любая попытка унаследоваться от него вызовет фатальную ошибку. Это используется, когда класс представляет законченную, неделимую сущность, расширение которой нарушило бы логику программы.

final class HashedPassword

{

    private string $hash;

    public function __construct(string $plainText)

    {

        $this->hash = password_hash($plainText, PASSWORD_BCRYPT);

    }

    public function verify(string $plainText): bool

    {

        return password_verify($plainText, $this->hash);

    }

}

// Это вызовет фатальную ошибку:

// class WeakPassword extends HashedPassword {}

// Fatal error: Class WeakPassword cannot extend final class HashedPassword

 

final перед методом

Можно запретить переопределение только одного конкретного метода, оставив сам класс открытым для наследования. Это тонкий инструмент: класс расширяется, но определённая часть его поведения остаётся неизменной.

class Notification

{

    public function __construct(

        protected string $recipient,

        protected string $body

    ) {}

    // Этот метод нельзя переопределить ни в одном потомке

    final public function getRecipient(): string

    {

        return $this->recipient;

    }

    // Этот метод можно переопределять

    public function format(): string

    {

        return "[{$this->recipient}] {$this->body}";

    }

}

 

class EmailNotification extends Notification

{

    // format() можно, он не final

    public function format(): string

    {

        return "Email: " . parent::format();

    }

    // getRecipient() нельзя, он final

    // public function getRecipient(): string { ... }

    // Fatal error: Cannot override final method Notification::getRecipient()

}

Не злоупотребляйте final. Излишнее его применение затрудняет тестирование: финальные классы нельзя мокировать стандартными инструментами. Помечайте как final только то, что действительно не должно меняться по архитектурным причинам.

 

Наследование в PHP — не просто способ «скопировать» код из одного класса в другой. Это инструмент выражения отношений между сущностями: дочерний класс является частным случаем родительского, уточняет его или расширяет.

Оператор final закрывает наследование там, где это необходимо по архитектурным соображениям — будь то весь класс или отдельный метод. Вместе эти инструменты дают полный контроль над тем, как классы в вашем приложении соотносятся друг с другом.

Лого

Spartacus_85 [Admin]

Администратор сайта — это специалист, который отвечает за техническую поддержку и бесперебойную работу веб-ресурса.



0 Комментарий(я)

Зарегистрируйтесь чтобы оставить комментарий