Наследование в 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: HybridCar наследует make, model и year (объявленные как protected, чтобы подкласс мог их использовать), повторно использует displayDetails() родителя через parent:: и добавляет собственную строку с fuelType.
Распространённые ошибки
privateне наследуется.private-свойство родителя невидимо для дочернего класса. Используйтеprotected, если подклассам нужен доступ.- Конструкторы не выстраиваются в цепочку автоматически, когда дочерний класс определяет собственный — всегда вызывайте
parent::__construct()самостоятельно. - PHP не поддерживает множественное наследование. Класс расширяет одного родителя; используйте интерфейсы или трейты для совместного использования поведения из нескольких источников.
- Переопределение молча игнорирует опечатки до PHP 8.3 — неправильно написанное имя метода просто создаёт новый метод вместо переопределения. Добавляйте
#[\Override]для безопасности.
Заключение
Наследование позволяет подклассу переиспользовать, переопределять и расширять члены родительского класса с помощью ключевого слова extends, а parent:: даёт доступ к исходной реализации. В сочетании с модификаторами видимости, конструкторами и final оно является основой повторного использования кода и полиморфизма в PHP OOP. Далее изучите абстрактные классы и интерфейсы для проектирования более чистых иерархий классов.