Ответ
DTO — это простой контейнер для данных, предназначенный только для их передачи между слоями приложения (например, из контроллера в сервис или через API). Внутри DTO не должно быть бизнес-логики.
Что должно быть внутри DTO:
- Приватные свойства (поля), представляющие данные.
- Конструктор для инициализации всех обязательных полей (часто используется подход "все или ничего").
- Геттеры для чтения данных. Сеттеры обычно нежелательны, чтобы сохранить иммутабельность (неизменяемость) объекта после создания.
- Базовая валидация данных в конструкторе (проверка типов, обязательных полей, простых инвариантов).
Пример DTO для регистрации пользователя на PHP:
final class UserRegistrationDto
{
public function __construct(
private string $email,
private string $plainPassword,
private string $name
) {
// Базовая валидация внутри DTO
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email format');
}
if (strlen($plainPassword) < 8) {
throw new InvalidArgumentException('Password must be at least 8 characters long');
}
}
public function getEmail(): string
{
return $this->email;
}
public function getPlainPassword(): string
{
return $this->plainPassword;
}
public function getName(): string
{
return $this->name;
}
}
// Использование
$dto = new UserRegistrationDto('user@example.com', 'securePass123', 'John Doe');
// Передаем DTO в сервис для дальнейшей обработки (хэширования пароля, сохранения в БД)
$userService->register($dto);
Чего НЕ должно быть в DTO:
- Сложной бизнес-логики (расчетов, взаимодействия с БД, внешними API).
- Аннотаций ORM (как в Doctrine Entity).
- Методов, изменяющих состояние, кроме конструктора.
Почему это важно: DTO отделяет формат передачи данных от внутренней доменной модели, что делает систему более гибкой и защищенной от изменений.