← Назад к вопросам

Часто ли используешь принципы SOLID?

1.6 Junior🔥 232 комментариев
#Архитектура и паттерны#Опыт и карьера

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Применение принципов SOLID в разработке на PHP

Как опытный backendPHP разработчик, я активно использую принципы SOLID и считаю их фундаментальными для создания устойчивого, масштабируемого и поддерживаемого кода. Это не просто абстрактные концепты, а практические инструменты, которые ежедневно влияют на архитектурные решения. Однако их применение всегда контекстуально: в крупных проектах со сложной бизнес-логикой они незаменимы, в небольших скриптах или прототипах — может быть минимальным.

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

S (Single Responsibility Principle - Принцип единственной ответственности)

Это самый часто применяемый принцип. Я строго слежу, чтобы каждый класс отвечал за одну конкретную задачу. Это резко снижает связанность кода и упрощает тестирование.

// ПЛОХО: Класс нарушает SRP, смешивая логику, сохранение и отправку email.
class BadOrderProcessor {
    public function process(Order $order) {
        // 1. Валидация и бизнес-логика
        if ($order->total <= 0) {
            throw new Exception('Invalid order');
        }
        // 2. Сохранение в базу данных
        $this->db->save($order);
        // 3. Коммуникация с пользователем
        $this->emailService->sendConfirmation($order);
    }
}

// ХОРОШО: Ответственности разделены на отдельные классы.
class OrderValidator {
    public function validate(Order $order): bool { /* ... */ }
}

class OrderRepository {
    public function save(Order $order): void { /* ... */ }
}

class OrderConfirmationNotifier {
    public function send(Order $order): void { /* ... */ }
}

// Координирующий сервис теперь зависит от абстракций.
class GoodOrderProcessor {
    public function __construct(
        private OrderValidator $validator,
        private OrderRepository $repository,
        private OrderConfirmationNotifier $notifier
    ) {}

    public function process(Order $order): void {
        $this->validator->validate($order);
        $this->repository->save($order);
        $this->notifier->send($order);
    }
}

O (Open/Closed Principle - Принцип открытости/закрытости)

Принцип особенно важен при разработке модулей, которые должны расширяться без модификации их исходного кода. Я достигаю этого через полиморфизм и использование интерфейсов (контрактов).

interface PaymentGatewayInterface {
    public function charge(Order $order): bool;
}

class StripeGateway implements PaymentGatewayInterface {
    public function charge(Order $order): bool { /* ... */ }
}

class PayPalGateway implements PaymentGatewayInterface {
    public function charge(Order $order): bool { /* ... */ }
}

class PaymentProcessor {
    // Класс закрыт для модификации (не нужно менять его код),
    // но открыт для расширения (можно добавить любой новый gateway).
    public function __construct(private PaymentGatewayInterface $gateway) {}

    public function executePayment(Order $order): void {
        $this->gateway->charge($order);
    }
}

L (Liskov Substitution Principle - Принцип подстановки Барбары Лисков)

Я применяю этот принцип, чтобы гарантировать, что наследники класса не нарушают контракт родителя. В PHP это означает строгий контроль за:

  • Сигнатурами методов (типы параметров и возвращаемых значений).
  • Семантикой методов (наследник не должен усиливать предconditions или ослаблять postconditions).
  • Не выбрасыванием новых исключений, не предусмотренных базовым классом.

Часто для соблюдения LSP приходится пересматривать иерархию классов и использовать более общие интерфейсы.

I (Interface Segregation Principle - Принцип разделения интерфейсов)

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

// Плохой, "жирный" интерфейс.
interface WorkerInterface {
    public function work(): void;
    public function eat(): void;
    public sleep(): void;
}

// Хорошо: интерфейсы разделены по контрактам.
interface WorkableInterface {
    public function work(): void;
}

interface EatableInterface {
    public function eat(): void;
}

class HumanEmployee implements WorkableInterface, EatableInterface {
    public function work(): void { /* ... */ }
    public function eat(): void { /* ... */ }
}

class RobotEmployee implements WorkableInterface {
    // Роботу не нужно есть, поэтому он реализует только нужный интерфейс.
    public function work(): void { /* ... */ }
}

D (Dependency Inversion Principle - Принцип инверсии зависимостей)

Это один из наиболее важных принципов в современном PHP, особенно в сочетании с Dependency Injection (DI) и контейнером зависимостей (например, Symfony Container). Я строю системы так, чтобы:

  • Модули высокого уровня (бизнес-логика) не зависели от модулей низкого уровня (конкретная реализация базы данных, HTTP-клиента).
  • Оба уровня зависели от абстракций (интерфейсов).
  • Абстракции не зависели от деталей реализации, а детали реализации зависели от абстракций.
// Высокоуровневая бизнес-логика зависит от абстракции.
class ReportGenerator {
    public function __construct(private DataSourceInterface $source) {}

    public function generate(): Report {
        $data = $this->source->fetchData(); // Не важно, где данные: DB, API, файл.
        // ... логика генерации отчета
    }
}

// Абстракция.
interface DataSourceInterface {
    public function fetchData(): array;
}

// Конкретная реализация низкого уровня зависит от абстракции.
class DatabaseDataSource implements DataSourceInterface {
    public function fetchData(): array { /* ... запрос к БД ... */ }
}

class ApiDataSource implements DataSourceInterface {
    public function fetchData(): array { /* ... запрос к внешнему API ... */ }
}

Итог и контекст применения

Я использую SOLID как систему взаимосвязанных принципов. Их совместное применение приводит к:

  • Снижению связанности (Coupling) и увеличению связности (Cohesion) кода.
  • Упрощению unit-тестирования благодаря легкой замене реальных зависимостей на mock/stub через интерфейсы.
  • Повышению гибкости системы: новые функции добавляются путем создания новых классов, а не переписывания существующих.
  • Облегчению чтения и поддержки кода для всей команды.

В фреймворках типа Symfony или Laravel, которые построены вокруг идеи DI и контейнеров услуг, соблюдение SOLID (особенно D и I) становится естественным и почти обязательным. В конечном счете, регулярное использование SOLID — это инвестиция в будущее проекта, которая экономит время и ресурсы на этапах расширения и долгосрочной поддержки.

Часто ли используешь принципы SOLID? | PrepBro