abstract
Ключевое слово abstract в PHP используется для определения абстрактных классов и методов.
Ключевое слово abstract в PHP
Ключевое слово abstract помечает класс или метод как намеренно незавершённый. Абстрактный класс определяет общую структуру и совместное поведение, но не может быть напрямую преобразован в object — он существует для расширения. Абстрактный метод объявляет сигнатуру метода без тела, обязывая каждый конкретный подкласс предоставить реализацию.
На этой странице рассматривается, что такое абстрактные классы и методы, как их объявлять, какие правила применяет PHP и когда использование abstract является правильным архитектурным решением.
Что такое абстрактный класс?
Абстрактный класс — это класс, который нельзя напрямую инстанцировать. Он предназначен для расширения другими классами, которые заполняют недостающие части. Абстрактный класс может сочетать два вида членов:
- Абстрактные методы — объявлены, но не реализованы; реализация возлагается на подклассы.
- Конкретные методы и свойства — полностью реализованы и наследуются как есть, поэтому общая логика сосредоточена в одном месте.
Правило действует в одну сторону: класс, содержащий хотя бы один абстрактный метод, обязан быть объявлен как abstract. Обратное необязательно — класс может быть абстрактным без каких-либо абстрактных методов, просто чтобы запретить его инстанцирование.
<?php
abstract class Animal {
// Concrete method — inherited by every subclass unchanged
public function describe(): string {
return "I am a " . static::class . " and I say " . $this->makeSound();
}
// Abstract method — each subclass must implement it
abstract public function makeSound(): string;
}Что такое абстрактный метод?
Абстрактный метод объявляется с ключевым словом abstract, не имеет тела и завершается точкой с запятой вместо { ... }. Его назначение — определить контракт: любой подкласс, претендующий на конкретность, обязан предоставить совместимую реализацию.
<?php
abstract public function makeSound(): string; // signature only, no bodyПодкласс должен сохранять совместимость с абстрактным объявлением — те же (или совместимые) параметры и видимость, равную или менее ограничивающую, чем у оригинала.
Как определить абстрактный класс и метод
Поставьте abstract перед class, чтобы сделать класс абстрактным, и перед function, чтобы сделать метод абстрактным. Ниже приведён полный пример — базовый класс с одним общим методом и одним абстрактным методом, а также два конкретных подкласса:
<?php
abstract class Animal {
public function describe(): string {
return static::class . " says " . $this->makeSound();
}
abstract public function makeSound(): string;
}
class Dog extends Animal {
public function makeSound(): string {
return "Woof!";
}
}
class Cat extends Animal {
public function makeSound(): string {
return "Meow!";
}
}
echo (new Dog())->describe(), "\n"; // Dog says Woof!
echo (new Cat())->describe(), "\n"; // Cat says Meow!Каждый подкласс реализует makeSound() и бесплатно наследует describe() — именно поэтому абстрактный базовый класс полезнее обычного интерфейса в данном случае.
Что происходит при попытке инстанцировать абстрактный класс?
Попытка создать object из абстрактного класса вызывает фатальную ошибку, обнаруживаемую на этапе компиляции:
<?php
abstract class Animal {
abstract public function makeSound(): string;
}
$a = new Animal();
// Fatal error: Cannot instantiate abstract class AnimalТа же ошибка возникает, если подкласс не реализует унаследованный абстрактный метод — PHP считает такой подкласс по-прежнему абстрактным.
Правила и особенности
- Класс с любым абстрактным методом обязан быть объявлен как
abstract. - Абстрактные методы не могут быть
private— подклассы не смогут их видеть для переопределения. Используйтеpublicилиprotected. - Абстрактные методы не могут быть
final(они предназначены для переопределения) и, начиная с PHP 8.0, не могут бытьstaticв полноценном переопределяемом смысле — предпочитайте экземплярные абстрактные методы. - Абстрактный класс может иметь конструктор; подклассы вызывают его через
parent::__construct(). - Подкласс, не реализующий все унаследованные абстрактные методы, сам должен быть объявлен как
abstract.
Абстрактный класс против интерфейса
Оба определяют контракт, но отвечают на разные вопросы:
- Абстрактный класс («является») может содержать конкретные методы, свойства и конструкторы. Класс может расширять только один абстрактный класс.
- Интерфейс («умеет делать») объявляет только сигнатуры методов (без реализации и состояния экземпляра), а класс может реализовывать множество интерфейсов.
Выбирайте абстрактный класс, когда подклассы разделяют реальную реализацию; выбирайте интерфейс, когда нужно лишь гарантировать наличие определённых возможностей. Подробнее см. PHP Inheritance и PHP Interfaces.
Заключение
Ключевое слово abstract позволяет определить частичный шаблон: абстрактный класс предоставляет общее поведение, объявляя при этом абстрактные методы, которые обязан реализовать каждый конкретный подкласс. Напрямую инстанцировать абстрактный класс нельзя — и в этом его смысл. Используйте его, когда несколько связанных классов разделяют общую логику, но каждый должен настраивать определённые шаги; выбирайте интерфейс, когда общая реализация не нужна.