Service Container
Service Container
Вступление
Сервисный контейнер Laravel является мощным инструментом для управления классовыми зависимостями и выполнения инъекций зависимостей. Инъекция зависимостей — это причудливая фраза, которая, по сути, означает следующее: классовые зависимости "инжектируются" в класс через конструктор или, в некоторых случаях, через методы "setter".
Давайте рассмотрим простой пример:
Глубокое понимание сервисного контейнера Laravel необходимо для создания мощного, крупного приложения, а также для внесения вклада в само ядро Laravel.
Биндинг
Основы биндинга
Простые биндинги
Внутри поставщика услуг вы всегда имеете доступ к контейнеру через свойство $this->app
. Мы можем зарегистрировать привязку, используя метод bind
, передав имя класса или интерфейса, который мы хотим зарегистрировать вместе с Closure
, который возвращает экземпляр класса:
Обратите внимание, что мы получаем сам контейнер в качестве аргумента в резолвер. Затем мы можем использовать контейнер для разрешения суб-зависимостей строящегося объекта.
Биндинг синглтона
Метод singleton
привязывает к контейнеру класс или интерфейс, который должен быть разрешен только один раз. Как только singleton-привязка будет разрешена, тот же самый экземпляр объекта будет возвращен при последующих вызовах в контейнер:
Биндинг экземпляра
Вы также можете привязать существующий экземпляр объекта к контейнеру с помощью метода instance
. Данный экземпляр всегда будет возвращаться при последующих обращениях в контейнер:
Биндинг интерфейса к реализации
Очень мощной особенностью сервисного контейнера является его способность привязывать интерфейс к заданной реализации. Например, предположим, что у нас есть интерфейс EventPusher
и реализация RedisEventPusher
. После того, как мы закодировали нашу реализацию RedisEventPusher
этого интерфейса, мы можем зарегистрировать его в сервисном контейнере таким образом:
Это выражение говорит контейнеру, что он должен внедрять RedisEventPusher
, когда классу нужна реализация EventPusher
. Теперь мы можем писать тайп-хинт на интерфейс EventPusher
в конструкторе, или в любом другом месте, где зависимости инжектируются сервисным контейнером:
Контекстный биндинг
Биндинг примитивов
Иногда вы можете иметь класс, который получает некоторые вводимые классы, но также нуждается в внедрении примитивного значения, такого как целое число. Вы можете легко использовать контекстную привязку, чтобы ввести любое значение, которое может понадобиться вашему классу:
Иногда класс может зависеть от массива тегированных экземпляров. Используя метод giveTagged
, можно легко ввести все привязки контейнеров с помощью этого тега:
Binding Typed Variadics
Иногда можно иметь класс, который получает массив типизированных объектов с помощью конструктора variadic:
Используя контекстную привязку, вы можете разрешить эту зависимость, предоставив метод give
с Closure, который возвращает массив разрешенных экземпляров Filter
:
Для удобства, вы также можете просто предоставить массив имен классов, которые будут разрешаться контейнером всякий раз, когда Firewall
нуждается в Filter
экземплярах:
Variadic Tag Dependencies
Иногда класс может иметь вариадическую зависимость, которая имеет тайп-хинт (Report ...$reports
). Используя методы needs
и giveTagged
, можно легко ввести все привязки контейнеров с этим тегом для данной зависимости:
Тегирование
Иногда может понадобиться решить все проблемы определенной "категории" привязки. Например, возможно, Вы строите агрегатор отчетов, который получает массив из множества различных реализаций интерфейса Report
. После регистрации реализаций Report
, Вы можете присвоить им тег, используя метод tag
:
После того, как сервисы будут тегированы, вы можете легко разрешить их все с помощью метода tagged
:
Расширенные биндинги
Метод extend
позволяет модифицировать разрешенные сервисы. Например, когда сервис разрешен, вы можете запустить дополнительный код для украшения или настройки сервиса. Метод extend
в качестве единственного аргумента принимает Closure, который должен возвращать модифицированный сервис. Closure получает разрешаемый сервис и экземпляр контейнера:
Разрешение
Метод make
make
Вы можете использовать метод make
для разрешения экземпляра класса из контейнера. Метод make
принимает имя класса или интерфейса, который вы хотите разрешить:
Если Вы находитесь в месте, где находится Ваш код, который не имеет доступа к переменной $app
, Вы можете воспользоваться глобальным помощником resolve
:
Если некоторые из зависимостей вашего класса не разрешимы через контейнер, вы можете внедрить их, передав в виде ассоциативного массива в метод makeWith
:
Автоматическое внедрение
Например, вы можете type-hint в конструкторе контроллера подсказку к репозиторию, определённому вашим приложением. Хранилище будет автоматически разрешено и внедрено в класс:
События контейнера
Сервисный контейнер запускает событие каждый раз при разрешении объекта. Вы можете прослушать это событие, используя метод resolving
:
Как видите, разрешаемый объект будет передан функции обратного вызова, что позволит вам установить любые дополнительные свойства на объекте до того, как он будет передан его потребителю.
PSR-11
Исключение бросается, если заданный идентификатор не может быть разрешен. Исключением будет экземпляр Psr\Container\NotFoundExceptionInterface
, если идентификатор никогда не был связан. Если идентификатор был связан, но не смог быть разрешен, то будет выброшен экземпляр Psr\Container\ContainerExceptionInterface
.
Last updated
Was this helpful?