Чем абстрактный класс отличается от интерфейса?php-13

Абстрактные классы и интерфейсы — это два ключевых инструмента для реализации полиморфизма и проектирования архитектуры приложения, но они служат разным целям.

Основные отличия

Характеристика Абстрактный класс Интерфейс
Экземпляр Нельзя создать напрямую Нельзя создать вообще
Свойства Может содержать свойства Только константы
Методы Может содержать реализацию Только сигнатуры методов
Модификаторы доступа Любые (public, protected, etc.) Только public
Наследование Один класс Множественное наследование
Конструктор Может иметь Не может иметь
Типизация Определяет "что есть" объект Определяет "что может" объект

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

abstract class Animal {
    protected $name;

    public function __construct($name) {
        $this->name = $name;
    }

    abstract public function makeSound();

    public function getName() {
        return $this->name;
    }
}

class Dog extends Animal {
    public function makeSound() {
        return "Woof!";
    }
}

Когда использовать:

  1. Когда несколько классов имеют общую логику
  2. Для частичной реализации функционала
  3. Когда нужно сохранять состояние (свойства)

Интерфейс

interface Loggable {
    public function log($message);
}

interface Cacheable {
    public function cache($data);
}

class DataProcessor implements Loggable, Cacheable {
    public function log($message) {
        file_put_contents('log.txt', $message);
    }

    public function cache($data) {
        // Реализация кэширования
    }
}

Когда использовать:

  1. Для определения контракта (что класс должен уметь)
  2. Когда нужно множественное наследование
  3. Для слабой связанности компонентов

Ключевые концептуальные различия

  1. Абстрактный класс — это частично реализованный класс ("is-a" отношение)

    • Например: Dog является Animal
  2. Интерфейс — это контракт ("can-do" отношение)

    • Например: DataProcessor умеет Loggable

Современные особенности

  1. Интерфейсы могут содержать константы
  2. Абстрактные методы могут иметь типизированные возвращаемые значения
  3. Интерфейсы могут включать методы по умолчанию (с PHP 8.1)
    interface Logger {
        public function log($message): void;
    
        default public function logError(string $error): void {
            $this->log("[ERROR] " . $error);
        }
    }
    

Практические рекомендации

  1. Используйте интерфейсы для:

    • Определения API
    • Полиморфного поведения
    • Тестирования (моки)
  2. Используйте абстрактные классы для:

    • Шаблонного метода
    • Частичной реализации
    • Общего состояния
  3. Комбинируйте их:

    abstract class Database implements Logger, Cacheable {
        // Общая реализация для всех БД
        abstract protected function connect();
    
        public function log($message) {
            // Базовая реализация
        }
    }
    

Резюмируем:

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