Наследование в PHP

Наследование — один из трёх китов объектно-ориентированного программирования. Оно позволяет выстраивать цепочки классов, в которых дочерний класс получает всё, что умеет родительский, и может дополнять или изменять это по своему усмотрению. В PHP наследование реализовано через ключевое слово extends и обладает рядом важных нюансов, которые стоит знать, чтобы не попасть в ловушку.

 

Что такое наследование и зачем оно нужно

Представьте, что вы разрабатываете систему уведомлений. У каждого типа уведомления есть общие черты: получатель, текст сообщения, дата отправки. Но способ доставки отличается: email, SMS, push-уведомление. Без наследования вам пришлось бы писать эти общие части заново для каждого класса. Наследование решает эту проблему: общий код живёт в одном месте — родительском классе, а дочерние классы берут его бесплатно и добавляют лишь своё уникальное поведение.

class Notification

{

    public function __construct(

        protected string $recipient,

        protected string $body,

        protected \DateTimeImmutable $sentAt = new \DateTimeImmutable()

    ) {}

    public function getSummary(): string

    {

        return "Кому: {$this->recipient} | {$this->sentAt->format('d.m.Y H:i')}";

    }

}

 

// EmailNotification наследует всё из Notification

class EmailNotification extends Notification

{

    public function __construct(

        string $recipient,

        string $body,

        private string $smtpServer = 'smtp.example.com'

    ) {

        parent::__construct($recipient, $body);

    }

    public function send(): void

    {

        echo "Email → {$this->recipient} через {$this->smtpServer}\n";

    }

}

 

$n = new EmailNotification('user@mail.ru', 'Ваш заказ принят');

echo $n->getSummary(); // метод унаследован от Notification

$n->send();             // Email → user@mail.ru через smtp.example.com

 

Переопределение функционала

Дочерний класс вправе объявить метод с тем же именем, что и в родителе. PHP будет вызывать версию дочернего класса — это называется переопределением, или overriding. Важное условие: сигнатура переопределённого метода должна быть совместима с родительской: нельзя добавить обязательные параметры или изменить тип возвращаемого значения на несовместимый.

class Notification

{

    public function format(): string

    {

        return "[Уведомление] {$this->body}";

    }

}

 

class UrgentNotification extends Notification

{

    // Переопределяем метод format() — PHP вызовет эту версию

    public function format(): string

    {

        return "???? [СРОЧНО] {$this->body}";

    }

}

 

$usual  = new Notification('admin', 'Плановое обновление');

$urgent = new UrgentNotification('admin', 'Сервер упал!');

echo $usual->format();  // [Уведомление] Плановое обновление

echo $urgent->format(); // ???? [СРОЧНО] Сервер упал!

 

Вызов родительского функционала

Переопределение не всегда означает полную замену. Часто нужно расширить поведение родителя, а не выбросить его. Для этого PHP предоставляет конструкцию parent:: — она позволяет явно вызвать метод или конструктор из родительского класса прямо внутри дочернего.

Это особенно важно в конструкторах: если родитель инициализирует свойства, а дочерний класс не вызовет parent::__construct(), эти свойства так и останутся пустыми.

class Notification

{

    public function __construct(

        protected string $recipient,

        protected string $body

    ) {

        echo "Notification создан\n";

    }

    public function format(): string

    {

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

    }

}

 

class LoggedNotification extends Notification

{

    private array $log = [];

    public function __construct(string $recipient, string $body)

    {

        parent::__construct($recipient, $body); // сначала инициализируем родителя

        $this->log[] = 'Создан: ' . date('H:i:s');

        echo "LoggedNotification создан\n";

    }

    public function format(): string

    {

        // Расширяем родительский format(), не заменяем его

        $base = parent::format();

        return $base . ' [запись в журнале]';

    }

    public function getLog(): array

    {

        return $this->log;

    }

}

 

$n = new LoggedNotification('ops@team.ru', 'Деплой завершён');

// Вывод:

// Notification создан

// LoggedNotification создан

echo $n->format();

// [ops@team.ru] Деплой завершён [запись в журнале]

 

parent:: всегда указывает на ближайшего родителя в цепочке наследования. Если классов несколько уровней, каждый вызывает parent:: своего непосредственного предка.

Лого

Spartacus_85 [Admin]

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



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

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