Урок по треку PHP 8 мин

Laravel: контейнер, middleware и очереди

Сервис-контейнер, провайдеры, фасады, middleware, валидация, очереди, Octane.

Laravel самый популярный PHP-фреймворк в российских продуктовых командах. На собесе спрашивают жизненный цикл запроса, сервис-контейнер, фасады, валидацию и очереди.

Жизненный цикл запроса

  1. public/index.php подключает автозагрузчик и создаёт приложение.
  2. Ядро загружает окружение, конфигурацию, обработку ошибок.
  3. Сервис-провайдеры: сначала у всех register(), потом у всех boot().
  4. Глобальные middleware, маршрутизатор находит маршрут, middleware маршрута.
  5. Контроллер с внедрёнными зависимостями возвращает ответ.
  6. Ответ проходит middleware обратно, затем terminable middleware.

В Laravel 11+ middleware, маршруты и обработка исключений настраиваются в bootstrap/app.php.

Сервис-контейнер

// AppServiceProvider::register()
$this->app->bind(PaymentGateway::class, YooKassaGateway::class);   // новый объект каждый раз
$this->app->singleton(TaxCalculator::class, fn() => new TaxCalculator(config('tax.rate')));
$this->app->scoped(CurrentTenant::class);                           // сбрасывается между запросами

$this->app->when(InvoiceMailer::class)
    ->needs(Mailer::class)
    ->give(SmtpMailer::class);                                      // контекстная привязка

Конкретные классы контейнер создаёт сам через рефлексию (auto-wiring), регистрировать нужно интерфейсы, синглтоны и объекты со скалярной конфигурацией.

Фасады

Cache::get('key') это статический прокси: __callStatic достаёт сервис cache из контейнера и вызывает метод. Поэтому фасады подменяются в тестах: Mail::fake(), Queue::fake(), Cache::shouldReceive(...). В своих сервисах лучше внедрять зависимости через конструктор: они видны в сигнатуре.

Middleware, валидация, авторизация

Route::middleware(['auth', 'throttle:60,1'])->group(function () {
    Route::post('/orders', [OrderController::class, 'store']);
});

class StoreOrderRequest extends FormRequest
{
    public function authorize(): bool { return $this->user()->can('create', Order::class); }
    public function rules(): array
    {
        return ['items' => ['required', 'array', 'min:1'], 'items.*.sku' => ['required', 'string']];
    }
}

FormRequest проверяет права и данные до контроллера и возвращает 422 с ошибками. Права на конкретный объект проверяют политики: $this->authorize('update', $order).

Очереди

class SendInvoice implements ShouldQueue
{
    use Queueable, SerializesModels;

    public int $tries = 5;
    public array $backoff = [10, 60, 300];

    public function __construct(public Order $order) {}
    public function handle(Mailer $mailer): void { ... }
    public function failed(Throwable $e): void { ... }
}

SendInvoice::dispatch($order)->onQueue('mail')->afterCommit();
  • SerializesModels кладёт в очередь только идентификатор модели, при выполнении она загружается заново.
  • Задание может выполниться больше одного раза: делайте его идемпотентным.
  • afterCommit: не ставить задание, пока транзакция не зафиксирована.
  • Redis + Horizon для мониторинга, отдельные очереди по приоритетам.
  • После деплоя php artisan queue:restart, против утечек --max-jobs, --max-time.

Octane

Octane (Swoole, RoadRunner, FrankenPHP) держит приложение в памяти между запросами. Скорость выше, но статика и синглтоны больше не сбрасываются сами: данные одного пользователя могут утечь в чужой запрос. Используйте scoped и не храните Request в синглтонах.

Деплой

composer install --no-dev -o, php artisan migrate --force, php artisan optimize (кеш конфигурации, маршрутов, представлений), queue:restart.

Частые ошибки

  • Логика в контроллерах и моделях вместо сервисов или actions.
  • $request->all() в create.
  • Синхронная отправка писем в запросе.
  • Задания, неидемпотентные при повторе.
  • env() вне конфигов: после config:cache он вернёт null.

Что спросят на собесе

  • Как проходит запрос через Laravel?
  • Как работает сервис-контейнер, чем bind отличается от singleton и scoped?
  • Что такое фасад и как его тестировать?
  • Как устроены очереди и как сделать задание надёжным?
  • Где валидировать данные и проверять права?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.