Ответ
Active Record (например, Laravel Eloquent):
- Плюсы:
- Простота и скорость разработки: Модель наследует базовый класс, который предоставляет все методы для CRUD (
find,save,delete). Это позволяет очень быстро создавать функциональность. - Прямой и понятный синтаксис: Работа с объектом интуитивно отражает работу с записью в БД.
- Быстрая настройка: Миграции, фабрики, сидеры тесно интегрированы в экосистему фреймворка.
- Простота и скорость разработки: Модель наследует базовый класс, который предоставляет все методы для CRUD (
- Минусы:
- Нарушение SRP (Single Responsibility Principle): Модель отвечает и за бизнес-логику, и за персистентность, что приводит к её «разбуханию».
- Сложность тестирования: Модель тесно связана с базой данных, что требует использования тестовой БД или моков для юнит-тестирования бизнес-логики.
- Сложность в сложных доменных моделях: При наличии сложных инвариантов, агрегатов и Value Objects архитектура Active Record становится громоздкой.
Data Mapper (например, Doctrine ORM):
- Плюсы:
- Чистая доменная модель: Сущность (Entity) — это обычный PHP-объект (POPO), не знающий ничего о базе данных. Это позволяет сосредоточиться на бизнес-логике.
- Гибкость и мощь: Позволяет эффективно работать со сложными связями (наследование, коллекции), агрегатами и кастомными типами данных.
- Лёгкость тестирования: Доменные объекты можно тестировать в полной изоляции, без зависимости от слоя персистентности.
- Разделение ответственности:
EntityManagerотвечает за сохранение и загрузку, репозитории — за запросы.
- Минусы:
- Более высокая сложность: Требует понимания дополнительных абстракций (Unit of Work, Identity Map).
- Больше шаблонного кода: Необходимо явно управлять жизненным циклом сущностей через
EntityManager(persist,flush). - Производительность в простых сценариях: Может быть избыточным для элементарных CRUD-операций.
Сравнительный пример:
// ### Active Record (Eloquent)
// app/Models/User.php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class User extends Model {
// Связи, аксессоры, мутаторы, скоупы пишутся здесь же
public function orders() {
return $this->hasMany(Order::class);
}
}
// Использование
$user = User::find(1); // Запрос в БД и создание объекта
$user->email = 'new@example.com';
$user->save(); // UPDATE запрос
// ### Data Mapper (Doctrine)
// src/Entity/User.php
namespace AppEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="users")
*/
class User {
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private ?int $id = null;
/**
* @ORMColumn(type="string")
*/
private string $email;
// Чистые геттеры и сеттеры, бизнес-методы
public function getEmail(): string { return $this->email; }
public function setEmail(string $email): void { $this->email = $email; }
}
// Использование (например, в контроллере)
$user = $entityManager->find(User::class, 1); // Загрузка из Identity Map или БД
$user->setEmail('new@example.com');
$entityManager->flush(); // Все изменения отслеживаемых сущностей будут сохранены
Вывод: Active Record отлично подходит для приложений с простой бизнес-логикой, прототипов и быстрой разработки. Data Mapper — это выбор для сложных предметных областей (Domain-Driven Design), где важны чистота модели, тестируемость и гибкость.