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