Какие паттерны проектирования знаете для организации слоя работы с базой данных?

«Какие паттерны проектирования знаете для организации слоя работы с базой данных?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В PHP-экосистеме распространены три основных паттерна для работы с БД, и я применял каждый в зависимости от контекста проекта:

1. Active Record Использовал в Laravel с Eloquent. Объект модели инкапсулирует и данные, и поведение для работы с ними. Паттерн прост для CRUD-операций.

// Модель User наследует IlluminateDatabaseEloquentModel
$user = new User();
$user->name = 'John';
$user->email = 'john@example.com';
$user->save(); // Выполняет INSERT

$foundUser = User::find(1); // Выполняет SELECT

Плюсы: Быстрое прототипирование, интуитивно понятный синтаксис. Минусы: Нарушает принцип единой ответственности (SRP), модель знает о БД, что усложняет тестирование.

2. Data Mapper Работал с ним через Doctrine ORM. Здесь модель (сущность) — это простой POPO (Plain Old PHP Object), а за отображение её состояния в БД отвечает отдельный класс-маппер.

// Сущность — простой класс
class User {
    private ?int $id = null;
    private string $name;
    // ... геттеры и сеттеры
}

// Маппер (в Doctrine это скрыто) отвечает за сохранение/загрузку
$entityManager->persist($user);
$entityManager->flush();

Плюсы: Чистая модель, независимая от слоя хранения. Минусы: Более высокая сложность и порог входа.

3. Repository Часто комбинирую его с Active Record или Data Mapper. Репозиторий абстрагирует все запросы к конкретной сущности, предоставляя коллекционный интерфейс.

class UserRepository {
    public function __construct(private User $model) {}

    public function findById(int $id): ?User {
        return $this->model->find($id);
    }
    public function findByEmail(string $email): ?User {
        return $this->model->where('email', $email)->first();
    }
}
// В сервисе
$user = $userRepository->findByEmail('test@example.com');

Плюсы: Централизация логики запросов, упрощение тестирования и смены реализации. Минусы: Добавляет слой абстракции, который может быть избыточным для простых задач.

На больших проектах предпочитаю комбинацию Data Mapper + Repository, а для средних и малых — Active Record с репозиториями для сложных запросов.