W3docs

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 позволяет определить частичный шаблон: абстрактный класс предоставляет общее поведение, объявляя при этом абстрактные методы, которые обязан реализовать каждый конкретный подкласс. Напрямую инстанцировать абстрактный класс нельзя — и в этом его смысл. Используйте его, когда несколько связанных классов разделяют общую логику, но каждый должен настраивать определённые шаги; выбирайте интерфейс, когда общая реализация не нужна.

Практика

Практика
Каковы правила использования абстрактных классов и методов в PHP согласно w3docs.com?
Каковы правила использования абстрактных классов и методов в PHP согласно w3docs.com?
Was this page helpful?