W3docs

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

Наследование в PHP позволяет создавать новые классы на основе существующих, переиспользуя свойства и методы через ключевое слово extends.

Наследование позволяет одному классу повторно использовать свойства и методы другого, моделируя отношения «является» (Car является Vehicle) без дублирования кода. В PHP это реализуется с помощью ключевого слова extends. В этой главе рассматриваются синтаксис, переопределение методов и ключевое слово parent, наследование конструкторов, роль модификаторов доступа и ключевого слова final, а также полный рабочий пример для экспериментов.

Если вы только начинаете изучать классы, сначала прочитайте Классы и объекты в PHP, а затем вернитесь сюда.

Что такое наследование?

Наследование — это возможность определить новый класс (дочерний, подкласс или производный класс) на основе существующего (родительского, суперкласса или базового класса). Дочерний класс автоматически получает public- и protected-члены родителя и может:

  • переиспользовать их без изменений,
  • переопределять их собственной реализацией, или
  • добавлять новые свойства и методы.

PHP поддерживает только одиночное наследование: класс может расширять ровно одного родителя. Однако можно выстраивать цепочкуHatchback extends Car extends Vehicle — и класс также может реализовывать множество интерфейсов, если нужно поведение из нескольких источников.

Преимущества наследования

  • Повторное использование — общая логика находится в родительском классе, поэтому вы пишете её один раз.
  • Поддерживаемость — исправление в родительском классе распространяется на все подклассы; меньше дублирования означает меньше мест для ошибок.
  • Полиморфизм — код, ожидающий Vehicle, работает с любым подклассом, что позволяет свободно менять реализации.
  • Чёткое моделирование — иерархия классов документирует отношения «является» в вашей предметной области.

Синтаксис наследования в PHP OOP

Чтобы создать подкласс, напишите extends с именем родительского класса:

class ChildClass extends ParentClass {
    // child-specific properties and methods
}

ChildClass теперь имеет все public- и protected-члены ParentClass. Обратите внимание, что private-члены родителя недоступны дочернему классу — используйте protected, если подклассам нужен доступ к члену, но он должен быть скрыт от внешнего кода. См. Модификаторы доступа в PHP для полного описания правил видимости.

Переопределение методов родительского класса

Подкласс переопределяет метод родителя, объявляя метод с тем же именем. Версия дочернего класса заменяет родительскую для объектов этого подкласса:

class ParentClass {
    public function displayMessage() {
        echo "Hello from ParentClass";
    }
}

class ChildClass extends ParentClass {
    public function displayMessage() {
        echo "Hello from ChildClass";
    }
}

Вызов метода родителя с помощью parent::

Переопределение не обязательно означает замену — зачастую вы хотите расширить поведение родителя. Используйте parent::, чтобы сначала вызвать версию родителя, а затем добавить своё:

class ChildClass extends ParentClass {
    public function displayMessage() {
        parent::displayMessage(); // runs the parent's logic
        echo " — and hello from ChildClass";
    }
}

Добавление атрибута #[\Override] (PHP 8.3+) над методом заставляет PHP выдавать ошибку, если метод на самом деле не переопределяет родительский — дешёвый способ поймать опечатки в именах методов.

Наследование и расширение конструкторов

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

class Vehicle {
    public function __construct(public string $make) {}
}

class Car extends Vehicle {
    public function __construct(string $make, public string $fuelType) {
        parent::__construct($make); // initialise the inherited part
    }
}

Подробнее о конструкторах см. в Конструктор PHP.

Запрет переопределения с помощью final

Пометьте метод как final, чтобы запретить подклассам его переопределять, или пометьте весь класс как final, чтобы полностью запретить его расширение:

class PaymentBase {
    final public function transactionId(): string {
        return 'TX-' . uniqid();
    }
}

Это полезно для логики, которая должна вести себя одинаково везде. Подробнее см. Ключевое слово final в PHP. Когда родительский класс должен определять сигнатуру метода, но обязывать каждого дочернего предоставить реализацию, вместо этого используйте абстрактный класс.

Пример наследования в PHP OOP

Ниже приведена полная рабочая программа. Базовый класс Vehicle хранит общие данные, а подкласс Car добавляет свойство fuelType и расширяет displayDetails() через parent:::

<?php

class Vehicle
{
    public function __construct(
        protected string $make,
        protected string $model,
        protected int $year
    ) {}

    public function displayDetails(): void
    {
        echo "Make: {$this->make}\n";
        echo "Model: {$this->model}\n";
        echo "Year: {$this->year}\n";
    }
}

class Car extends Vehicle
{
    public function __construct(
        string $make,
        string $model,
        int $year,
        protected string $fuelType
    ) {
        parent::__construct($make, $model, $year);
    }

    public function displayDetails(): void
    {
        parent::displayDetails();           // reuse the parent's output
        echo "Fuel Type: {$this->fuelType}\n"; // then add our own
    }
}

$car = new Car('Toyota', 'Corolla', 2023, 'Hybrid');
$car->displayDetails();

Вывод:

Make: Toyota
Model: Corolla
Year: 2023
Fuel Type: Hybrid

Car наследует make, model и year (объявленные как protected, чтобы подкласс мог их использовать), повторно использует displayDetails() родителя через parent:: и добавляет собственную строку с fuelType.

Распространённые ошибки

  • private не наследуется. private-свойство родителя невидимо для дочернего класса. Используйте protected, если подклассам нужен доступ.
  • Конструкторы не выстраиваются в цепочку автоматически, когда дочерний класс определяет собственный — всегда вызывайте parent::__construct() самостоятельно.
  • PHP не поддерживает множественное наследование. Класс расширяет одного родителя; используйте интерфейсы или трейты для совместного использования поведения из нескольких источников.
  • Переопределение молча игнорирует опечатки до PHP 8.3 — неправильно написанное имя метода просто создаёт новый метод вместо переопределения. Добавляйте #[\Override] для безопасности.

Заключение

Наследование позволяет подклассу переиспользовать, переопределять и расширять члены родительского класса с помощью ключевого слова extends, а parent:: даёт доступ к исходной реализации. В сочетании с модификаторами видимости, конструкторами и final оно является основой повторного использования кода и полиморфизма в PHP OOP. Далее изучите абстрактные классы и интерфейсы для проектирования более чистых иерархий классов.

Практика

Практика
Какие из следующих утверждений о наследовании в PHP верны?
Какие из следующих утверждений о наследовании в PHP верны?
Was this page helpful?