Питання на співбесіді: Service Container
Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів
3 питання
Service Container (IoC-контейнер) керує залежностями класів і виконує dependency injection. Він уміє автоматично будувати об'єкти, рекурсивно резолвлячи їхні залежності через type-hints конструктора.
// біндинг інтерфейсу до реалізації (зазвичай у Service Provider)
$this->app->bind(PaymentGateway::class, StripeGateway::class);
// тепер усюди, де просять PaymentGateway, прийде StripeGateway
public function __construct(private PaymentGateway $gateway) {}
bind()- нова реалізація щоразу.singleton()- один екземпляр на весь життєвий цикл запиту.app(PaymentGateway::class)- ручне резолвлення.
Це серце Laravel: контролери, middleware, події - усе резолвиться через контейнер.
Dependency Injection - патерн, за якого клас отримує залежності ззовні (зазвичай через конструктор), а не створює їх сам. Це знижує зв'язування й полегшує тестування (можна підсунути мок).
class OrderController
{
public function __construct(
private PaymentGateway $gateway, // інжектується контейнером
) {}
}
У Laravel DI працює «з коробки»: контейнер читає type-hints і автоматично будує граф залежностей. Інжектити можна й у методи контролера (method injection), зокрема сам Request.
Contextual binding дозволяє віддавати різні реалізації одного інтерфейсу залежно від класу, що його запитує.
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(fn () => Storage::disk('local'));
$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(fn () => Storage::disk('s3'));
Тобто PhotoController отримає локальний диск, VideoController - S3, хоча обидва просять Filesystem.
Споріднені можливості:
giveTagged()- впорснути всі сервіси з певним тегом.- Прив'язка примітивів:
->needs('$apiKey')->give(config('services.x.key')).
Корисно, коли одна абстракція має кілька конфігурацій у різних частинах застосунку.