Single Responsibility Principle (SRP) — принцип единственной ответственности
SRP (Single Responsibility Principle) — это первый и, пожалуй, самый фундаментальный принцип из SOLID. Он гласит:
Класс должен иметь только одну причину для изменения.
Проще говоря — класс должен отвечать за что-то одно.
Если класс делает слишком много вещей, он становится трудно поддерживаемым, сложным для тестирования и увеличивает риск ошибок при изменениях.
❌ Плохой пример: класс делает слишком много
class UserRegistration
{
public function register(array $data): void
{
// 1. Валидация
if (empty($data['email'])) {
throw new Exception('Email required');
}
// 2. Сохранение в базу
// ... код сохранения ...
// 3. Отправка письма
mail($data['email'], 'Welcome!', 'Thank you for registration');
// 4. Логирование
file_put_contents('log.txt', "User {$data['email']} registered\n", FILE_APPEND);
}
}
Этот класс нарушает SRP, потому что отвечает сразу за:
- валидацию
- работу с базой
- отправку email
- логирование
Любое изменение (например, смена SMTP-сервера) требует правок в этом же классе.
✅ Хороший пример: разделяем ответственностиclass Validator
{
public function validateRegistration(array $data): void
{
if (empty($data['email'])) {
throw new Exception('Email required');
}
}
}
class UserRepository
{
public function save(array $data): void
{
// код сохранения в базу
}
}
class Mailer
{
public function sendWelcome(string $email): void
{
// отправка письма
}
}
class Logger
{
public function log(string $message): void
{
file_put_contents('log.txt', $message . "\n", FILE_APPEND);
}
}
class UserRegistrationService
{
public function __construct(
private Validator $validator,
private UserRepository $users,
private Mailer $mailer,
private Logger $logger
) {}
public function register(array $data): void
{
$this->validator->validateRegistration($data);
$this->users->save($data);
$this->mailer->sendWelcome($data['email']);
$this->logger->log("User {$data['email']} registered");
}
}
Теперь:
- каждый класс отвечает за свою задачу;
- менять или тестировать каждую часть проще;
- UserRegistrationService стал оркестратором, а не “монстр-классом”.
🔍 Как понять, что класс нарушает SRP?
Задай себе три вопроса:
- Есть ли у этого класса несколько ролей?
- Если в системе изменится X, нужно ли менять этот класс?
- Трудно ли описать назначение класса одним предложением?
Если ты не можешь кратко объяснить, чем занимается класс — он точно нарушает SRP.
📌 Где чаще всего нарушается SRP?
- Контроллеры, которые делают и валидацию, и бизнес-логику.
- Модели, которые одновременно отвечают за данные, валидацию, отправку писем, логику.
- Сервисы, которые со временем обрастают множеством несвязанных методов.
- Помощники и Utils, куда скидывают всё подряд.
🧩 Итог
SRP помогает писать код, который:
- проще поддерживать;
- легче тестировать;
- легче расширять;
- понятнее другим разработчикам.
Это фундамент для всей архитектуры.
Если не соблюдать SRP — остальные принципы SOLID тоже дадутся тяжелее.