#Введение
Провайдеры сервисов — это центральное место для загрузки всех компонентов приложения Laravel. Ваше приложение, а также все основные сервисы Laravel загружаются через провайдеры сервисов.
Но что мы подразумеваем под «загрузкой»? В общем случае это означает регистрацию различных элементов, включая регистрацию привязок в сервис-контейнере, слушателей событий, middleware и даже маршрутов. Провайдеры сервисов — это центральное место для настройки вашего приложения.
Если открыть файл config/app.php, который поставляется с Laravel, вы увидите массив providers. В нем перечислены все классы провайдеров сервисов, которые будут загружены для вашего приложения. По умолчанию в этом массиве указан набор основных провайдеров Laravel. Эти провайдеры загружают основные компоненты Laravel, такие как почтовый сервис, очередь, кэш и другие. Многие из этих провайдеров являются «отложенными», то есть они не загружаются при каждом запросе, а только тогда, когда действительно нужны предоставляемые ими сервисы.
В этом обзоре вы узнаете, как создавать собственные провайдеры сервисов и регистрировать их в вашем приложении Laravel.
Если вы хотите узнать больше о том, как Laravel обрабатывает запросы и работает внутри, ознакомьтесь с нашей документацией по жизненному циклу запроса.
#Создание провайдеров сервисов
Все провайдеры сервисов наследуются от класса Illuminate\Support\ServiceProvider. Большинство провайдеров содержат методы register и boot. В методе register вы должны только регистрировать привязки в сервис-контейнере. Никогда не пытайтесь регистрировать слушателей событий, маршруты или другие функциональные элементы в методе register.
CLI Artisan может сгенерировать новый провайдер с помощью команды make:provider:
php artisan make:provider RiakServiceProvider
#Метод Register
Как уже упоминалось, внутри метода register следует только вносить привязки в контейнер служб. Никогда не пытайтесь регистрировать какие-либо обработчики событий, маршруты или любую другую часть функциональности внутри метода register. Иначе вы можете случайно использовать сервис, предоставляемый сервис-провайдером, который ещё не был загружен.
Рассмотрим простой пример провайдера сервисов. В любом методе вашего провайдера у вас всегда есть доступ к свойству $app, которое предоставляет доступ к сервис-контейнеру:
<?php
namespace App\Providers;
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider
{
/**
* Регистрация сервисов приложения.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection(config('riak'));
});
}
}
Этот провайдер сервисов определяет только метод register и использует его для регистрации реализации App\Services\Riak\Connection в сервис-контейнере. Если вы еще не знакомы с сервис-контейнером Laravel, ознакомьтесь с его документацией.
#Свойства bindings и singletons
Если ваш провайдер регистрирует много простых привязок, вы можете использовать свойства bindings и singletons вместо ручной регистрации каждой привязки. Когда провайдер загружается фреймворком, он автоматически проверяет эти свойства и регистрирует их привязки:
<?php
namespace App\Providers;
use App\Contracts\DowntimeNotifier;
use App\Contracts\ServerProvider;
use App\Services\DigitalOceanServerProvider;
use App\Services\PingdomDowntimeNotifier;
use App\Services\ServerToolsProvider;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Все привязки контейнера, которые должны быть зарегистрированы.
*
* @var array
*/
public $bindings = [
ServerProvider::class => DigitalOceanServerProvider::class,
];
/**
* Все синглтоны контейнера, которые должны быть зарегистрированы.
*
* @var array
*/
public $singletons = [
DowntimeNotifier::class => PingdomDowntimeNotifier::class,
ServerProvider::class => ServerToolsProvider::class,
];
}
#Метод Boot
Что если нам нужно зарегистрировать view composer в нашем провайдере? Это следует делать в методе boot. Этот метод вызывается после регистрации всех остальных провайдеров, что означает, что у вас есть доступ ко всем сервисам, зарегистрированным фреймворком:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Загрузка сервисов приложения.
*/
public function boot(): void
{
View::composer('view', function () {
// ...
});
}
}
#Внедрение зависимостей в метод Boot
Вы можете указывать типы зависимостей для метода boot вашего провайдера. Сервис-контейнер автоматически внедрит необходимые зависимости:
use Illuminate\Contracts\Routing\ResponseFactory;
/**
* Загрузка сервисов приложения.
*/
public function boot(ResponseFactory $response): void
{
$response->macro('serialized', function (mixed $value) {
// ...
});
}
#Регистрация провайдеров
Все провайдеры сервисов регистрируются в конфигурационном файле config/app.php. В этом файле есть массив providers, в котором можно перечислить имена классов ваших провайдеров. По умолчанию в этом массиве зарегистрирован набор основных провайдеров Laravel. Эти провайдеры загружают основные компоненты Laravel, такие как почтовый сервис, очередь, кэш и другие.
Чтобы зарегистрировать свой провайдер, добавьте его в массив:
'providers' => ServiceProvider::defaultProviders()->merge([
// Другие провайдеры сервисов
App\Providers\ComposerServiceProvider::class,
])->toArray(),
#Отложенные провайдеры
Если ваш провайдер только регистрирует привязки в сервис-контейнере, вы можете отложить его регистрацию до тех пор, пока одна из зарегистрированных привязок не понадобится. Отложенная загрузка такого провайдера улучшит производительность вашего приложения, так как он не будет загружаться из файловой системы при каждом запросе.
Laravel компилирует и сохраняет список всех сервисов, предоставляемых отложенными провайдерами, вместе с именем класса провайдера. Затем провайдер загружается только в тот момент, когда вы пытаетесь разрешить один из этих сервисов.
Чтобы отложить загрузку провайдера, реализуйте интерфейс \Illuminate\Contracts\Support\DeferrableProvider и определите метод provides. Метод provides должен возвращать привязки сервис-контейнера, зарегистрированные провайдером:
<?php
namespace App\Providers;
use App\Services\Riak\Connection;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Регистрация сервисов приложения.
*/
public function register(): void
{
$this->app->singleton(Connection::class, function (Application $app) {
return new Connection($app['config']['riak']);
});
}
/**
* Получить сервисы, предоставляемые провайдером.
*
* @return array<int, string>
*/
public function provides(): array
{
return [Connection::class];
}
}