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.