Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Senior: питання на співбесіді з теми «Сервіс-провайдери»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

2 питання

Кожен провайдер завантажується на кожному запиті. Якщо він лише реєструє сервіс, потрібний в одному місці з сотні, це марна робота на всіх інших запитах.

Відкладений провайдер реєструється лише тоді, коли його сервіс справді резолвлять:

use Illuminate\Contracts\Support\DeferrableProvider;

class WeatherServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(WeatherClient::class, function ($app) {
            return new WeatherClient(config('services.weather.key'));
        });
    }

    /**
     * @return array<int, class-string>
     */
    public function provides(): array
    {
        return [WeatherClient::class];
    }
}

Laravel запамʼятовує зіставлення «сервіс → провайдер» у маніфесті й піднімає провайдер лише за потреби.

Умови, за яких це працює:

  • Провайдер має лише register(). Якщо є boot(), слухачі подій, маршрути чи публікація ресурсів - вони не виконаються, поки сервіс ніхто не запросить, тобто фактично ніколи.
  • provides() мусить перелічувати всі привʼязки. Забута привʼязка просто не знайдеться в контейнері.

Коли не варто: якщо провайдер реєструє щось, що потрібне майже завжди, відкладення дає нуль виграшу й додає місце для помилки.

Скільки це коштує. Виграш помітний на застосунку з десятками провайдерів; на невеликому - в межах похибки. Перед тим як відкладати, варто виміряти профайлером, а не робити це «про всяк випадок».

Докладніше в документації: Сервіс-провайдери

Через package discovery: пакет оголошує провайдер і фасади в секції extra.laravel свого composer.json.

"extra": {
    "laravel": {
        "providers": [
            "Acme\\Billing\\BillingServiceProvider"
        ],
        "aliases": {
            "Billing": "Acme\\Billing\\Facades\\Billing"
        }
    }
}

Після composer install чи update Laravel виконує package:discover, збирає ці оголошення з усіх пакетів і кешує список. Провайдер реєструється автоматично - у bootstrap/providers.php нічого дописувати не треба.

Як застосунку відмовитися від автопідключення - наприклад, щоб зареєструвати провайдер умовно лише локально:

"extra": {
    "laravel": {
        "dont-discover": ["barryvdh/laravel-debugbar"]
    }
}

"*" у dont-discover вимикає виявлення для всіх пакетів.

Що варто знати авторові пакета:

  • провайдер пакета має бути легким і бажано відкладеним, якщо лише реєструє прив'язки - він завантажується в кожному застосунку, що встановив пакет;
  • конфігурацію, міграції й шаблони пакет пропонує опублікувати (publishes()), а не копіює сам;
  • mergeConfigFrom() у register() дає значення за замовчуванням, які застосунок може перекрити своїм файлом.

Якщо після встановлення пакета щось «не підхопилося», перевіряють кеш: php artisan package:discover і optimize:clear.

Докладніше в документації: Виявлення пакетів