Ответ
В 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) на основе конфигурации.
- Сложных зависимостей: Когда объект требует нескольких других сервисов и конфигурационных данных для инициализации.