← Назад к вопросам
В чем разница между интерфейса от абстрактного класса?
2.2 Middle🔥 231 комментариев
#ООП
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Разница между интерфейсом и абстрактным классом
Это классический вопрос в ООП, и в PHP эта разница достаточно ясна. Рассмотрим оба подхода.
Интерфейс (Interface)
Интерфейс - это контракт, определяющий какие методы должны быть реализованы, но БЕЗ реализации самих методов:
interface PaymentInterface {
public function pay(float $amount): bool;
public function refund(float $amount): bool;
public function getTransactionId(): string;
}
Характеристики:
- Только public методы (PHP 8.1+)
- Нет реализации (только сигнатуры)
- Нет свойств (только константы)
- Класс может реализовать множество интерфейсов (implements A, B, C)
- Фокус на КОНТРАКТЕ, а не на реализации
Абстрактный класс (Abstract Class)
Абстрактный класс - это частично реализованный класс, который нельзя инстанцировать напрямую:
abstract class PaymentProvider {
protected string $apiKey;
public function __construct(string $apiKey) {
$this->apiKey = $apiKey;
}
abstract public function pay(float $amount): bool;
// Конкретная реализация
public function getBalance(): float {
return $this->fetchBalance();
}
protected function fetchBalance(): float {
// Реализация
return 1000.0;
}
}
Характеристики:
- Может иметь как абстрактные методы, так и конкретные реализации
- Может иметь свойства (protected, private)
- Может иметь конструктор и другую инициализацию
- Класс может наследовать только ОДИН абстрактный класс (extends)
- Фокус на ПОВТОРНОМ ИСПОЛЬЗОВАНИИ КОДА
Основные различия в таблице
| Критерий | Интерфейс | Абстрактный класс |
|---|---|---|
| Инстанцирование | ❌ Нельзя | ❌ Нельзя |
| Методы | Только сигнатуры | Могут быть реализованы |
| Свойства | ❌ Нет | ✅ Да (public/protected/private) |
| Конструктор | ❌ Нет | ✅ Да |
| Множественное наследование | ✅ Да (implements A, B, C) | ❌ Нет (extends X только) |
| Модификаторы доступа методов | Только public | public/protected/private |
| Константы | ✅ Да | ✅ Да |
Когда использовать что?
Используй ИНТЕРФЕЙС когда:
// Хочешь определить контракт поведения для разных типов
interface NotificationInterface {
public function send(string $message): bool;
}
class EmailNotification implements NotificationInterface {
public function send(string $message): bool {
// Email отправка
return true;
}
}
class SMSNotification implements NotificationInterface {
public function send(string $message): bool {
// SMS отправка
return true;
}
}
class SlackNotification implements NotificationInterface {
public function send(string $message): bool {
// Slack отправка
return true;
}
}
// В коде работаешь с интерфейсом
function notifyUser(NotificationInterface $notifier, string $msg) {
$notifier->send($msg);
}
- Разные реализации одного поведения
- Dependency Injection и Loose Coupling
- Тестирование (мокирование интерфейса)
- SOLID - Interface Segregation Principle
Используй АБСТРАКТНЫЙ КЛАСС когда:
// Есть общий код и логика для группы связанных классов
abstract class Repository {
protected PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
// Общий код для всех репозиториев
public function findById(int $id): ?array {
$stmt = $this->db->prepare('SELECT * FROM ' . $this->table() . ' WHERE id = ?');
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
// Абстрактный метод - каждый репозиторий сам решает
abstract protected function table(): string;
}
class UserRepository extends Repository {
protected function table(): string {
return 'users';
}
public function findByEmail(string $email): ?array {
$stmt = $this->db->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
}
- Общее функционал для иерархии классов
- Государство и инициализация (конструктор)
- Переиспользование кода через наследование
- Template Method паттерн
Best Practice в современных проектах
В PHP рекомендуется:
- Программировать на интерфейсах - это делает код более гибким
- Минимизировать глубину наследования - лучше композиция
- Использовать Dependency Injection - работа через интерфейсы
- Абстрактные классы для реальных иерархий - когда есть по-настоящему общий код
// Хороший пример архитектуры
interface UserServiceInterface {
public function register(string $email, string $password): User;
public function login(string $email, string $password): ?User;
}
class UserService implements UserServiceInterface {
public function __construct(
private UserRepository $userRepository,
private PasswordHasher $hasher
) {}
public function register(string $email, string $password): User {
// Реализация
}
}
Это позволяет легко тестировать, мокировать и менять реализацию без изменения интерфейса.