Laravel: Сервис Контейнер — что нужно знать новичкам

Источник: «Laravel Service Container: What Beginners Need to Know»
Сервис Контейнер (Контейнер Служб), пожалуй, одна из самых запутанных тем для новичков в Laravel. Официальная документация объясняет его хорошо, но с большим количеством теоретических слов. Давайте приступим к практике, и я покажу основные практические примеры, которые вам нужно знать.

Первое: в большинстве случаев вам никогда не придётся работать напрямую с Сервис Контейнером. Для новичков достаточно понять, что Сервис Контейнер — это внутренний механизм Laravel, который позволяет делать определённые инъекции классов авто-магически, вот и всё.

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

Простой пример: Класс Запроса Формы

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

// UserController.php:
public function store(StoreUserRequest $request) {
User::create($request->validated());
// ...
}

Видите этот StoreUserRequest, как объявление типа в методе? Это типичный класс Запроса Формы Заметили, что мы не инициализируем экземпляр этого класса? Laravel сделает это за нас, если мы укажем его как объявление типа в методе.

Другими словами, нам не нужно делать это вручную внутри метода:

$request = new StoreUserRequest();

Так что это делает Сервис Контейнер, он разрешает экземпляр этого класса и автоматически создаёт объект для нас.

Другой типичный пример: Внедрение метода контроллера

Мы часто хотим использовать внешние классы в наших контроллерах. В курсе о структуре проекта Laravel я обсуждал различные используемые классы: Сервисы, Action и т.д. Возьмём в качестве примера Сервисы.

Вопрос: как инициализировать сервисный класс, чтобы использовать его внутри нашего контроллера?

Самый простой способ:

// UserController.php:
public function store(StoreUserRequest $request) {
$userService = new UserService();
$userService->create($request->validated());
}

Но что, если я вам скажу, что не нужно инициализировать сервис с помощью new UserService()? И, может быть, вы догадались, чем именно Сервис Контейнер может нам помочь?

Вот ответ:

public function store(StoreUserRequest $request, UserService $userService) {
$userService->create($request->validated());
}

Да, мы просто добавляем класс, который хотим использовать внутри метода, с указанием типа, и Laravel автоматически создаст свою переменную для использования внутри метода.

И вы можете сделать это в любом методе в ваших контроллерах.

Сервис Контейнер работает только для методов? Что насчёт конструкторов?

Я рад, что вы спросили. Довольно часто вам нужно использовать класс в нескольких методах контроллера.

Итак, неудобный способ:

public function store(StoreUserRequest $request, UserService $userService) {
$userService->create($request->validated());
}

public function update(User $user, UpdateUserRequest $request, UserService $userService) {
$userService->update($user, $request->validated());
}

Можем ли мы инициализировать UserService для всего контроллера? Конечно!

public function __construct(public UserService $userService)
{
}

public function store(StoreUserRequest $request) {
$this->userService->create($request->validated());
}

public function update(User $user, UpdateUserRequest $request) {
$this->userService->update($user, $request->validated());
}

Обратите внимание: мы используем одну из функций PHP 8 - объявление свойств в конструкторе, поэтому конструктор пуст.

Сервис Контейнер работает только в контроллерах?

Согласно официальной документации, нет:

Вы можете объявить тип зависимости в конструкторе класса, которая решается контейнером, включая контроллеры, слушатели событий, посредники и т.д. Кроме того, вы можете объявить тип зависимости в методе handle обработки заданий поставленных в очередь.

Не уверен, что означает это и т.д., но вы можете попробовать использовать Сервис Контейнер в любом другом классе Laravel и посмотреть работали он.

Теперь, если у вас есть свой собственный PHP класс и вы попытаетесь использовать этот трюк, это не сработает, потому что Laravel не узнает об этом.

Например, если у вас есть Сервисный PHP класс:

class UserService {

public function __construct(SomeOtherService $someService) {}

}

Это не сработает.

Продвинутый уровень: Ручная привязка и другое

В принципе, приведённой выше информации достаточно для начинающих, чтобы знать её на практическом уровне. Вам необязательно знать как работает Сервис Контейнер внутри, или как связать/разрешить зависимые классы в более сложных случаях.

Но если вы хотите узнать об этом… вы можете, конечно, прочитать всю страницу официальной документации.

Дополнительные материалы

Предыдущая Статья

Laravel: Как работает cron и планировщик задач

Следующая Статья

Laravel: переносим Контроллер в Сервисный Класс с внедрением