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

Как разбиваешь слои архитектуры?

2.3 Middle🔥 181 комментариев
#Архитектура и паттерны

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

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

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

Подход к разделению слоев архитектуры в PHP Backend

При проектировании backend-приложений на PHP я придерживаюсь принципа разделения ответственности (Separation of Concerns), используя многоуровневую архитектуру. Вот мой стандартный подход:

Основные архитектурные слои

1. Доменный слой (Domain Layer)

Содержит бизнес-логику и сущности, полностью независимые от инфраструктуры.

// Пример доменной сущности
class Order {
    private OrderId $id;
    private CustomerId $customerId;
    private OrderItems $items;
    private OrderStatus $status;
    
    public function place(): void {
        if ($this->items->isEmpty()) {
            throw new EmptyOrderException();
        }
        $this->status = OrderStatus::PLACED();
        $this->recordEvent(new OrderPlaced($this->id));
    }
}

2. Слой приложения (Application Layer)

Координирует выполнение use cases, выступая как посредник между внешним миром и доменом.

class PlaceOrderService {
    public function __construct(
        private OrderRepository $repository,
        private EventDispatcher $dispatcher
    ) {}
    
    public function execute(PlaceOrderCommand $command): OrderId {
        $order = Order::create(
            $command->customerId,
            $command->items
        );
        
        $order->place();
        
        $this->repository->save($order);
        $this->dispatcher->dispatchEvents(
            $order->releaseEvents()
        );
        
        return $order->getId();
    }
}

3. Инфраструктурный слой (Infrastructure Layer)

Реализует технические детали: работу с БД, внешними API, кэшем, файловой системой.

class DoctrineOrderRepository implements OrderRepository {
    public function __construct(
        private EntityManager $em
    ) {}
    
    public function save(Order $order): void {
        $this->em->persist($order);
        $this->em->flush();
    }
}

4. Слой представления/доступа (Interface/Adapter Layer)

Обрабатывает входящие запросы (HTTP, CLI, очереди) и возвращает ответы.

class OrderController {
    public function __construct(
        private PlaceOrderService $service,
        private OrderPresenter $presenter
    ) {}
    
    public function placeOrder(Request $request): JsonResponse {
        $command = new PlaceOrderCommand(
            $request->get('customer_id'),
            $request->get('items')
        );
        
        $orderId = $this->service->execute($command);
        
        return $this->presenter->present($orderId);
    }
}

Ключевые принципы разделения

Направление зависимостей всегда идет от внешних слоев к внутренним:

  • Внутренние слои (домен) ничего не знают о внешних
  • Внешние слои зависят от внутренних

Маркеры правильного разделения:

  • Возможность тестировать бизнес-логику без БД и HTTP
  • Замена инфраструктуры (например, MySQL на PostgreSQL) без изменения домена
  • Независимое развитие слоев разными командами

Практические паттерны реализации

Для простых проектов часто использую порты-адаптеры (Hexagonal):

App/
├── Domain/          # Ядро бизнес-логики
├── Application/     # Use cases, сервисы приложения
├── Infrastructure/  # Реализации репозиториев, внешние сервисы
└── UI/             # Контроллеры, консольные команды

Для сложных систем применяю модульную организацию по бизнес-контекстам (DDD Bounded Contexts):

App/
├── OrderModule/
│   ├── Domain/
│   ├── Application/
│   └── Infrastructure/
├── CustomerModule/
│   ├── Domain/
│   └── Application/
└── Shared/
    └── Kernel/     # Общая инфраструктура

Конкретные техники в PHP

Внедрение зависимостей через интерфейсы:

interface OrderRepository {
    public function save(Order $order): void;
    public function findById(OrderId $id): ?Order;
}

// Инфраструктурный слой реализует интерфейс из доменного
class PostgreSQLOrderRepository implements OrderRepository {
    // Реализация с использованием конкретной БД
}

DTO для передачи данных между слоями:

class OrderDetailsDTO {
    public function __construct(
        public readonly string $orderId,
        public readonly array $items,
        public readonly string $status
    ) {}
}

Преимущества такого подхода

  • Тестируемость: Домен тестируется юнит-тестами без инфраструктуры
  • Поддерживаемость: Изменения в одном слое минимально затрагивают другие
  • Гибкость: Легкая замена компонентов (например, переход на другой фреймворк)
  • Масштабируемость: Возможность распределения слоев по разным серверам

Разделение слоев — это баланс между чистотой архитектуры и практической целесообразностью. Для стартапов иногда достаточно простой 3-слойной архитектуры (Controller-Service-Repository), тогда как для enterprise-систем требуется полноценное разделение с четкими границами контекстов.