Сервисы в Symfony: коротко, просто и понятно

Сервисы в Symfony: коротко, просто и понятно

Довольно просто и доступно о том, что из себя представляют сервисы и как они работают в Symfony 4 (по материалам symfonycasts).

OS: Ubuntu 18.04, Framework: Symfony 4.2.5

Итак, что такое сервис? На самом деле, за этим термином стоит довольно простая идея: сервис - это любой объект, который выполняет какую-то работу. Например, отправляет сообщения, сохраняет данные в базу, парсит RSS и т.д.

Как использовать сервисы? Просто внутри контроллера добавьте в метод дополнительный аргумент и дайте ему подсказку типа, например, LoggerInterface и назовите его как хотите, например $logger:

public function index(LoggerInterface $logger)
{
    // do something
    $logger->info('Some message');
}

Как это работает? Перед тем, как запустить контроллер, Symfony проверяет каждый аргумент, смотрит на подсказку типа и понимает, что нам нужен тот или иной объект. И, кстати, порядок аргументов вовсе не важен.

Symfony поставляется с огромным количеством сервисов. Как узнать, какие сервисы доступны? Войдите в корневую директорию проекта и выполните команду:

bin/console debug:autowiring

 

Можно также выполнить поиск по ключевому слову:

bin/console debug:autowiring [<keyword>]

 

Ок, а что такое autowiring? Это автоматическое подключение, которое позволяет управлять сервисами с минимумом конфигурации. Речь об этом уже была выше - Symfony читает подсказку типа и передаёт нужный объект. Как насчёт пользовательского кода? Откройте файл config/services.yaml и обратите внимание на следующие строки:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

 

Это означает, что любой класс (подробнее ниже) автоматически зарегистрирован как сервис и автоматически подключен. Другими словами, созданные классы можно сразу же использовать как сервисы, вообще не задумываясь о конфигурации. 

Стоп! Неужели вообще любой класс зарегистрирован как сервис? Вообще-то нет. Опять обратимся к файлу config/services.yaml:

services:
    ...
    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

 

Т.е. все классы в директории src, кроме тех, которые находятся в поддиректориях перечисленных в exclude, будут доступны как сервисы.

Откуда берутся объекты сервисов? Каждый сервис, хранится внутри другого объекта, который называется контейнером (также называемый сервис-контейнером или контейнером инъекции зависимостей). Важный момент: объект сервиса создаётся только тогда, когда Вы его запрашиваете. Если этого не происходит то и сервис не будет создан, что способствует экономии памяти и скорости. Кроме того сервис создаётся только один раз, т.е. каждый раз Symfony будет возвращать один и тот же экземпляр сервиса.

Но как сервисы попадают в контейнер, кто их туда кладёт? Ответ: бандлы. Бандлы подобны плагинам в других программном обеспечении. Ключевое отлие в том, что в Symfony всё является бандлами, включая как ядро фреймворка, так и код написанный для Вашего приложения. 

И напоследок: Symfony - это не что иное, как набор сервисов. А бандлы - это то, что фактически готовит сервисы и помещает их в контейнер.

Надеюсь, после этой статьи картина стала понятнее. При этом как обычно, рекомендую тщательно изучить официальную документацию, поскольку некоторые важные моменты не были затронуты в данной статье (явная конфигурация сервисов и параметров, привязка аргументов по имени или типу, публичные и приватные сервисы и т.д.)

Успехов!