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

Работа с объектами иногда может быть сложной, особенно если вы не знаете, какую структуру вам нужно использовать. Например, как абстрактные классы, так и интерфейсы могут заставить другие классы реализовать некоторые методы.

Интерфейсы — это «контракты».

Классы, реализующие интерфейс, должны реализовывать его методы.

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


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


Другой вопрос, является ли термин «контракт» лучшим для описания интерфейсов.

Проблема здесь в том, чтобы понять, когда вам, вероятно, следует использовать интерфейс вместо абстрактного класса, и наоборот.

Только сигнатуры методов?

И интерфейсы, и абстрактные классы могут содержать сигнатуры методов, которые должны быть реализованы использующими их классами.

interface LoggingInterface
{
    public function warning($message, array $context = array()): void;
}

abstract class Logging
{
    abstract public function warning($message, array $context = array()): void;
}

Обе структуры не могут быть созданы и должны быть реализованы (интерфейсы) или расширены (абстрактные классы). Однако интерфейсы не могут иметь свойства и функциональные возможности (методы с телом).

Какая тогда разница?

Классы PHP могут реализовывать несколько интерфейсов, но невозможно расширить несколько классов.

ИМХО, это ключ к пониманию того, когда следует использовать интерфейсы или абстрактные классы.


Если вам нужно передать некоторые функциональные возможности (не абстрактные) и свойства группе классов, абстрактные классы могут оказаться полезными. Если вы хотите только гарантировать, что ваши классы будут реализовывать определенное поведение, используйте интерфейсы.


В нашем примере выше интерфейс кажется более подходящим, и он нужен не только для того, чтобы гарантировать, что метод warning() будет реализован с определенной сигнатурой.

Используйте обе структуры для улучшения вашего кода.

Независимо от того, используете ли вы интерфейсы или абстрактные классы, обычно это лучший подход, чем классические расширения или большие случаи переключения.


Код также должен быть более читабельным, поскольку вы можете исключить множество if условий и предотвратить ненужные повторения.


Конечно, написать плохой код по-прежнему можно, но эти структуры помогут вам найти свой путь.


Интерфейсы и абстрактные классы очень похожи, но абстрактный класс похож на базовый код для ваших объектов, который может обеспечить реализацию по умолчанию, поэтому классы, расширяющие их, обычно связаны. Напротив, интерфейсы фокусируются на поведении и могут группировать несвязанные классы.