Что дает использование сервис-провайдеров:
1. Сервис провайдеры реализуют механизм «Dependency Injection», что переводится как «Внедрение зависимостей». Это позволяет разграничить «зоны ответственности» классов, уменьшить их связанность, а так же дает упрощение доступа к нужным объектам.
Для получения доступа к сервисам можно как использовать внедрение зависимостей:
public function form(SaveStr $save){}так и получать нужные объекты прямо из сервис-контейнера, в котором они регистрировались:
App::make('App\Helpers\Contracts\SaveStr')
2. Сервис-провайдеры лежат в основе «первоначальной загрузки» всего Laravel. То есть, с их помощью загружаются служебные классы, нужные для работы фреймворка.
3. При регистрации классов-сервисов в глобальном объекте с помощью сервис-провайдеров, обычно используется шаблон проектирования «синглтон». Это значит, что при работе приложения, независимо от количества обращений к объекту сервиса используя глобальный объект – мы работаем с одним и тем же объектом-сервисом с теми свойствами, которые были установлены ранее. Таким образом, на одном этапе мы записали какие-то свойства, далее, в любом классе и методе их получили. Ну и, разумеется не нужно каждый раз создавать объект класса-сервиса для работы.
4. Метод boot() удобное место для регистрации слушателей событий, посредников и даже маршрутов. Т.к. данный метод всех сервис-провайдеров вызывается автоматически после загрузки приложения и в нем уже есть доступ к использованию фасадов и любых сервисов из сервис-контейнера.
Все классы сервис-провайдеров наследуются от класса ServiceProvider и, обычно, содержат методы register() и boot().
В файле config/app.php перечислены все сервис-провайдеры.
Пользовательские (дополнительные) классы сервис-провайдеров размещают в папке app\Providers.
При загрузке фреймворка вызывается метод register() для каждого из классов сервис-провайдера, который осуществляет привязку своего класса(сервиса), по текстовому ключу, к глобальному объекту для последующего облегчения доступа путем внедрения зависимости в нужном методе нужного класса:
public function show(Request $request){}
Сразу или при первом вызове метода register() (зависит от того, является ли провайдер «отложенным»), создается объект данных классов (сервисов), который потом используется (в основном используется шаблон проектирования «синглтон»):
public function register() { $this->app->singleton('App\Helpers\Contracts\SaveStr', function(){ return new SaveEloquent(); });в качестве первого параметра метода singleton() глобального объекта App передается полный путь к классу (а обычно интерфейсу-контракту, если такой есть), в качестве второго параметра – анонимная функция возвращающая создаваемый объект нужного класса.
Привязывать обычный класс, не реализующий никакой интерфейс, обычно нет смысла, если только потом не собираетесь сделать фасад для быстрого доступа к сервису такого класса.
Вместо $this->app можно использовать фасад App:
App::singleton(SaveStr::class, function(){ return new SaveEloquent(); });
Так же можно сделать привязку класса к сервис-контейнеру уже при выполнении пользовательского кода, например в контроллере:
app()->singleton('App\Helpers\Contracts\SaveStr', function(){ return new App\Helpers\SaveEloquent(); });
При создании фасадов для работы со своими сервисами (упрощение доступа к методам сервисов), в качестве первого аргумента передается не контракт или класс, а алиас, к которому потом нужно будет обращаться для вызова методов классов-сервисов:
App::singleton('save', function(){ return new SaveEloquent(); });
Методы boot() сервис-провайдеров вызывается автоматически после того, как все другие сервис-провайдеры были зарегистрированы. Это значит, что в них есть доступ ко всем другим сервисам, которые были зарегистрированы фреймворком.
Примеры создания и использования сервис-провайдеров можно увидеть в статье Архитектура Laravel - практическое применение.