Интерфейсы и абстрактные классы в PHP

Интерфейсы и абстрактные классы в PHP: interface, implements, abstract class, контракты и когда что выбирать.

Абстрактный класс — это класс-заготовка, который нельзя создать напрямую. Интерфейс — это контракт: набор методов, которые класс обязуется реализовать. Оба инструмента помогают строить гибкую и расширяемую архитектуру.

Абстрактный класс

Абстрактный класс объявляется с ключевым словом abstract. В нём могут быть как обычные методы с реализацией, так и абстрактные — без тела. Потомок обязан реализовать все абстрактные методы:

<?php
abstract class Shape {
    abstract public function area(): float; // без реализации — потомок обязан!

    public function describe(): string {
        return "Фигура с площадью: " . $this->area();
    }
}

class Circle extends Shape {
    public function __construct(private float $radius) {}

    public function area(): float {
        return M_PI * $this->radius ** 2;
    }
}

class Rectangle extends Shape {
    public function __construct(
        private float $width,
        private float $height,
    ) {}

    public function area(): float {
        return $this->width * $this->height;
    }
}

$shapes = [new Circle(5), new Rectangle(4, 6)];
foreach ($shapes as $shape) {
    echo $shape->describe() . "\n";
}

// new Shape(); // Fatal error: Cannot instantiate abstract class

Вывод:

Фигура с площадью: 78.539816339745
Фигура с площадью: 24

Интерфейс

Интерфейс — это чистый контракт без реализации. Класс «подписывается» на него через implements. Один класс может реализовывать несколько интерфейсов одновременно:

<?php
interface Drawable {
    public function draw(): string;
}

interface Resizable {
    public function resize(float $factor): void;
}

class Canvas implements Drawable, Resizable {
    public function __construct(private float $size = 100) {}

    public function draw(): string {
        return "Рисую холст размером {$this->size}px";
    }

    public function resize(float $factor): void {
        $this->size *= $factor;
    }
}

$canvas = new Canvas();
echo $canvas->draw();   // Рисую холст размером 100px
$canvas->resize(1.5);
echo $canvas->draw();   // Рисую холст размером 150px

Вывод:

Рисую холст размером 100px
Рисую холст размером 150px

Абстрактный класс vs Интерфейс

Абстрактный классИнтерфейс
Реализация методовможет бытьнет (кроме default)
Свойстваестьнет
Наследованиетолько однонесколько сразу
Смысл«является» (Cat — Animal)«умеет» (Canvas — Drawable)

Правило: если классы разделяют общий код — используйте абстрактный класс. Если нужно описать способность, которую могут иметь несвязанные классы — используйте интерфейс.

Коротко

  • Абстрактный класс не создаётся через new; его абстрактные методы обязан реализовать потомок.
  • Интерфейс — только контракт; класс реализует его через implements.
  • Один класс может реализовывать несколько интерфейсов, но расширять только один класс.
  • Абстрактный класс = общая природа, интерфейс = общая способность.
Проверьте себя
1. Можно ли создать объект абстрактного класса через new?
AДа, если не все методы абстрактные
BДа, если конструктор публичный
CНет, абстрактный класс нельзя инстанциировать
DТолько внутри самого класса через static
2. Сколько интерфейсов может реализовывать один класс PHP?
AТолько один
BНе более двух
CНеограниченно — через запятую
DТолько если они наследуют общий базовый интерфейс
3. Когда стоит выбрать интерфейс вместо абстрактного класса?
AКогда нужно поделиться общим кодом между похожими классами
BКогда несвязанные классы должны поддерживать одну и ту же способность
CКогда нужно объявить protected-свойства
DКогда класс наследует только один родительский
Поддержать проект