Через властивості $bindings і $singletons замість викликів у register().
class AppServiceProvider extends ServiceProvider
{
public array $bindings = [
ServerProvider::class => DigitalOceanServerProvider::class,
];
public array $singletons = [
DowntimeNotifier::class => PingdomDowntimeNotifier::class,
ServerToolsProvider::class => ServerToolsProvider::class,
];
}
Фреймворк сам пройде ці масиви, коли завантажуватиме провайдер, і зареєструє кожну пару «абстракція - реалізація».
Коли цього досить: прив'язка інтерфейсу до класу, який контейнер може створити сам.
Коли потрібен register(): якщо об'єкт треба створити по-особливому - з параметрами з конфігурації, з умовою, з замиканням:
public function register(): void
{
$this->app->singleton(PaymentGateway::class, fn () => new StripeGateway(
config('services.stripe.secret'),
));
}
Ще одна зручність: метод boot() теж підтримує впровадження залежностей - потрібні сервіси оголошують його параметрами, а не дістають через $this->app->make().
public function boot(ResponseFactory $response): void
{
$response->macro('caps', fn (string $value) => $response->make(strtoupper($value)));
}
Докладніше в документації: Властивості bindings і singletons