В предыдущей статье мы подробно разобрали **классы в PHP** — основу объектно-ориентированного программирования. Теперь перейдём к следующему важному понятию ООП: **интерфейсам**. Если класс — это «чертёж объекта», то интерфейс — это «договор», по которому класс обязуется реализовать определённое поведение.
Интерфейсы позволяют писать гибкий, расширяемый и тестируемый код. Они лежат в основе принципов SOLID, особенно **принципа инверсии зависимостей (DIP)** и **принципа разделения интерфейсов (ISP)**.
Что такое интерфейс?
**Интерфейс** в PHP — это абстрактный тип, который определяет **контракт**: набор методов, которые должен реализовать любой класс, его реализующий. Сам интерфейс **не содержит реализации** — только сигнатуры методов (имя, параметры, возвращаемое значение).
>
Интерфейс отвечает на вопрос: «Что может делать объект?», но не «Как он это делает?».
Базовый синтаксис
Объявление интерфейса:
Реализация интерфейса классом:
- Ключевое слово `interface` — для объявления интерфейса.
- Ключевое слово `implements` — для подключения интерфейса к классу.
- Класс **обязан реализовать все методы**, объявленные в интерфейсе, с той же сигнатурой (включая типы параметров и возвращаемого значения).
## Зачем нужны интерфейсы? Основные преимущества
1. Гарантия совместимости
Если функция ожидает объект, реализующий интерфейс `Logger`, вы можете передать **любой** класс, реализующий этот интерфейс — `FileLogger`, `DatabaseLogger`, `EmailLogger` и т.д.
Это называется **полиморфизмом** — один и тот же код работает с разными реализациями.
2. Лёгкое тестирование
Благодаря интерфейсам вы можете легко подменить реальные зависимости на **моки** (заглушки) при тестировании:
3. Слабая связанность (loose coupling)
Классы зависят не от конкретных реализаций, а от абстракций. Это упрощает изменение кода: вы можете заменить `FileLogger` на `CloudLogger`, и остальной код **не потребует изменений**, если оба реализуют один и тот же интерфейс.
Интерфейсы vs Абстрактные классы
Множественная реализация интерфейсов
Класс может реализовывать **несколько** интерфейсов:
Это особенно полезно для микросервисной архитектуры и компонентного подхода.
Интерфейсы с методами по умолчанию (PHP 8.0+)
Начиная с **PHP 8.0**, в интерфейсах можно определять **методы с телом** (но только как `public` и без свойств):
>
Однако злоупотреблять этим не стоит — интерфейсы по-прежнему должны оставаться **контрактами**, а не местом для общей логики. Для повторного использования кода лучше использовать **трейты**.
Трейты vs Интерфейсы
- **Трейт (trait)** — механизм повторного использования кода («горизонтальное наследование»).
- **Интерфейс** — контракт поведения.
Часто они используются **вместе**:
Такой подход сочетает **гибкость интерфейсов** и **удобство трейтов**.
Практический пример: система оплаты
Представим, что вы разрабатываете интернет-магазин с поддержкой разных платёжных систем.
Благодаря интерфейсу `PaymentGateway` вы легко можете:
- Добавлять новые платёжные системы.
- Писать автотесты с моками.
- Менять провайдеров без переписывания логики заказа.
Советы по проектированию интерфейсов
1. **Именуйте интерфейсы как прилагательные или существительные действия**:
`Loggable`, `Renderable`, `PaymentGateway`, `Authenticatable`.
2. **Следуйте принципу разделения интерфейсов (ISP)**:
Лучше создать несколько узкоспециализированных интерфейсов, чем один «божественный».
3. **Не добавляйте методы «на всякий случай»** — интерфейс должен отражать реальные потребности.
4. **Используйте скалярные типы и строгую типизацию** (PHP 7.0+), чтобы усилить контракт.
Заключение
Интерфейсы — это не просто синтаксическая конструкция PHP, а **инструмент проектирования**. Они помогают:
- Писать код, который легко менять и расширять.
- Упрощать тестирование.
- Соблюдать принципы чистой архитектуры.
- Избегать «жёсткой привязки» к конкретным реализациям.
Освоив интерфейсы, вы сделаете важный шаг к профессиональному уровню в PHP-разработке. В следующей статье цикла мы рассмотрим **трейты (traits)** — ещё один мощный механизм повторного использования кода в PHP.
>
**Помните**: интерфейсы — это не «дополнение», а основа современного, гибкого и поддерживаемого кода.
*Статья актуальна для PHP 8.3 (на момент написания: январь 2026 г.).*
Интерфейсы позволяют писать гибкий, расширяемый и тестируемый код. Они лежат в основе принципов SOLID, особенно **принципа инверсии зависимостей (DIP)** и **принципа разделения интерфейсов (ISP)**.
Что такое интерфейс?
**Интерфейс** в PHP — это абстрактный тип, который определяет **контракт**: набор методов, которые должен реализовать любой класс, его реализующий. Сам интерфейс **не содержит реализации** — только сигнатуры методов (имя, параметры, возвращаемое значение).
>
Базовый синтаксис
Объявление интерфейса:
PHP:
interface Logger {
public function log(string $message): void;
}
Реализация интерфейса классом:
PHP:
class FileLogger implements Logger {
public function log(string $message): void {
file_put_contents('app.log', $message . PHP_EOL, FILE_APPEND);
}
}
- Ключевое слово `interface` — для объявления интерфейса.
- Ключевое слово `implements` — для подключения интерфейса к классу.
- Класс **обязан реализовать все методы**, объявленные в интерфейсе, с той же сигнатурой (включая типы параметров и возвращаемого значения).
## Зачем нужны интерфейсы? Основные преимущества
1. Гарантия совместимости
Если функция ожидает объект, реализующий интерфейс `Logger`, вы можете передать **любой** класс, реализующий этот интерфейс — `FileLogger`, `DatabaseLogger`, `EmailLogger` и т.д.
PHP:
function processUser(Logger $logger) {
// ... какая-то логика ...
$logger->log("Пользователь обработан");
}
$logger = new FileLogger();
processUser($logger); // Работает!
$logger = new DatabaseLogger();
processUser($logger); // Тоже работает!
Это называется **полиморфизмом** — один и тот же код работает с разными реализациями.
2. Лёгкое тестирование
Благодаря интерфейсам вы можете легко подменить реальные зависимости на **моки** (заглушки) при тестировании:
PHP:
class MockLogger implements Logger {
public array $messages = [];
public function log(string $message): void {
$this->messages[] = $message;
}
}
// В юнит-тесте
$mock = new MockLogger();
processUser($mock);
assert(in_array("Пользователь обработан", $mock->messages));
3. Слабая связанность (loose coupling)
Классы зависят не от конкретных реализаций, а от абстракций. Это упрощает изменение кода: вы можете заменить `FileLogger` на `CloudLogger`, и остальной код **не потребует изменений**, если оба реализуют один и тот же интерфейс.
Интерфейсы vs Абстрактные классы
| Характеристика | Интерфейс | Абстрактный класс |
| Может содержать реализацию методов | Нет (до PHP 8.0); с PHP 8.0 — да, через trait или методы с телом (см. ниже) | Да |
| Может содержать свойства | Нет | Да (включая protected/private) |
| Множественное наследование | Да (implements A, B, C) | Нет (extends только один |
| Конструктор | Нельзя | Можно |
| Типичное использование | Определение поведения (что делает?) | Общая логика (как делает?) |
Множественная реализация интерфейсов
Класс может реализовывать **несколько** интерфейсов:
PHP:
interface Loggable {
public function log(string $msg): void;
}
interface Notifiable {
public function notify(string $msg): void;
}
class AdminService implements Loggable, Notifiable {
public function log(string $msg): void {
// запись в лог
}
public function notify(string $msg): void {
// отправка уведомления
}
}
Это особенно полезно для микросервисной архитектуры и компонентного подхода.
Интерфейсы с методами по умолчанию (PHP 8.0+)
Начиная с **PHP 8.0**, в интерфейсах можно определять **методы с телом** (но только как `public` и без свойств):
PHP:
interface Renderable {
public function render(): string;
// Метод с реализацией по умолчанию
public function display(): void {
echo $this->render();
}
}
class HtmlPage implements Renderable {
public function render(): string {
return "<h1>Привет, мир!</h1>";
}
}
$page = new HtmlPage();
$page->display(); // Выведет: <h1>Привет, мир!</h1>
>
Трейты vs Интерфейсы
- **Трейт (trait)** — механизм повторного использования кода («горизонтальное наследование»).
- **Интерфейс** — контракт поведения.
Часто они используются **вместе**:
PHP:
trait LoggableTrait {
public function log(string $msg): void {
error_log($msg);
}
}
interface Loggable {
public function log(string $msg): void;
}
class UserService implements Loggable {
use LoggableTrait; // Реализация берётся из трейта
}
Такой подход сочетает **гибкость интерфейсов** и **удобство трейтов**.
Практический пример: система оплаты
Представим, что вы разрабатываете интернет-магазин с поддержкой разных платёжных систем.
PHP:
interface PaymentGateway {
public function charge(float $amount): bool;
public function refund(float $amount): bool;
}
class StripeGateway implements PaymentGateway {
public function charge(float $amount): bool {
// интеграция со Stripe API
return true;
}
public function refund(float $amount): bool {
// возврат через Stripe
return true;
}
}
class PayPalGateway implements PaymentGateway {
public function charge(float $amount): bool {
// интеграция с PayPal
return true;
}
public function refund(float $amount): bool {
// возврат через PayPal
return true;
}
}
class OrderService {
public function __construct(
private PaymentGateway $gateway
) {}
public function completeOrder(float $total): void {
if ($this->gateway->charge($total)) {
echo "Заказ оплачен!";
}
}
}
// Гибкое использование
$order = new OrderService(new StripeGateway());
$order->completeOrder(99.99);
// Или
$order = new OrderService(new PayPalGateway());
$order->completeOrder(99.99);
Благодаря интерфейсу `PaymentGateway` вы легко можете:
- Добавлять новые платёжные системы.
- Писать автотесты с моками.
- Менять провайдеров без переписывания логики заказа.
Советы по проектированию интерфейсов
1. **Именуйте интерфейсы как прилагательные или существительные действия**:
`Loggable`, `Renderable`, `PaymentGateway`, `Authenticatable`.
2. **Следуйте принципу разделения интерфейсов (ISP)**:
Лучше создать несколько узкоспециализированных интерфейсов, чем один «божественный».
3. **Не добавляйте методы «на всякий случай»** — интерфейс должен отражать реальные потребности.
4. **Используйте скалярные типы и строгую типизацию** (PHP 7.0+), чтобы усилить контракт.
Заключение
Интерфейсы — это не просто синтаксическая конструкция PHP, а **инструмент проектирования**. Они помогают:
- Писать код, который легко менять и расширять.
- Упрощать тестирование.
- Соблюдать принципы чистой архитектуры.
- Избегать «жёсткой привязки» к конкретным реализациям.
Освоив интерфейсы, вы сделаете важный шаг к профессиональному уровню в PHP-разработке. В следующей статье цикла мы рассмотрим **трейты (traits)** — ещё один мощный механизм повторного использования кода в PHP.
>
*Статья актуальна для PHP 8.3 (на момент написания: январь 2026 г.).*