Назови случай, когда в Laravel нужно передавать параметры в конструктор

Ответ

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

<?php

namespace AppServicesPayment;

interface PaymentGateway
{
    public function charge(float $amount): bool;
}

class StripeGateway implements PaymentGateway
{
    private string $apiKey;
    private bool $useSandbox;

    // Контейнер не может сам "угадать" строку $apiKey и булевый $useSandbox
    public function __construct(string $apiKey, bool $useSandbox = false)
    {
        $this->apiKey = $apiKey;
        $this->useSandbox = $useSandbox;
    }

    public function charge(float $amount): bool
    {
        // Использование $this->apiKey и $this->useSandbox
        return true;
    }
}

// В сервис-провайдере явно указываем, как создать экземпляр
class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(PaymentGateway::class, function ($app) {
            return new StripeGateway(
                config('services.stripe.secret_key'), // Примитивный параметр
                config('app.env') === 'local'          // Условный параметр
            );
        });
    }
}

// Теперь в контроллере или другом классе зависимость внедрится автоматически
class PaymentController extends Controller
{
    public function __construct(private PaymentGateway $gateway) {}

    public function store(PaymentRequest $request)
    {
        $this->gateway->charge($request->amount);
    }
}

Такой подход также полезен для:

  • Тестирования: Можно легко подменить реализацию в тестах, передав мок.
  • Условного внедрения: Например, выбрать драйвер кэша (redis или file) на основе конфигурации.
  • Сложных зависимостей: Когда объект требует нескольких других сервисов и конфигурационных данных для инициализации.

Ответ 18+ 🔞

Э, слушай, а вот это реально частая засада, когда Laravel не может сам разобраться, что ему в конструктор пихать. Представь себе — контейнер он умный, но не телепат, ёпта. Если ты ему суёшь в конструктор какую-нибудь строку или булево значение, он такой: «Чувак, а откуда я, блядь, знаю, какой у тебя там $apiKey? В конфиге лежит? В .env? Сам-то подумай!»

Вот смотри на примере этого платежного шлюза. Интерфейс есть, класс реализует его, всё красиво. Но конструктор-то требует конкретные примитивы!

public function __construct(string $apiKey, bool $useSandbox = false)
{
    $this->apiKey = $apiKey;
    $this->useSandbox = $useSandbox;
}

Контейнер смотрит на это и просто охуевает. «string $apiKey»? Ну я не знаю, братан, какую строку тебе дать! «bool $useSandbox»? Может true, может false — хуй его знает! Доверия к его догадкам — ебать ноль.

Поэтому приходится в сервис-провайдере всё разжевать, как младенцу. Смотри:

$this->app->bind(PaymentGateway::class, function ($app) {
    return new StripeGateway(
        config('services.stripe.secret_key'), // Вот, держи свою строку из конфига
        config('app.env') === 'local'          // А булево значение сам посчитай на основе окружения
    );
});

Вот тут мы ему явно говорим: «Слушай сюда, когда кому-то понадобится PaymentGateway, ты не еби мозг, просто создай StripeGateway и воткни в него эти два параметра». И контейнер такой: «А, ну теперь понятно, спасибо, что просветил».

А дальше — магия. В контроллере ты просто объявляешь зависимость в конструкторе, и Laravel, уже наученный, подставляет тебе готовый, настроенный объект. Удобно же, блядь!

public function __construct(private PaymentGateway $gateway) {}

И в методе просто юзаешь, нихуя не паришься.

А ещё это овердохуища полезно для:

  • Тестирования. Захотел — в тестах подсунул мок этой зависимости, который не будет реально слать запросы в Stripe, а просто скажет, что всё ок. Красота.
  • Условного внедрения. Типа: «Окружение продакшн? — Дай ему редис. Окружение локальное? — Пусть файловый кэш юзает, нахуй». Всё решается в том же провайдере.
  • Сложных зависимостей. Бывают такие монстры-сервисы, которым при создании нужен и репозиторий, и логгер, и конфиг, и ещё три других сервиса. Контейнер и тут справится, если всё правильно забиндить. Главное — помочь ему, этот ёперный театр, сам он с такими головоломками не справится.

Короче, смысл в том, чтобы не надеяться на авось, а явно сказать фреймворку: «Вот, дружок, вот рецепт, как эту хрень собирать». И тогда жить станет проще, а код — предсказуемее.