Laravel Service Container: What Beginners Need to Know

Service Container is probably one of the most confusing topics for beginners in Laravel. The official docs explain it well but with a lot of "theoretical words". Let's get practical and I'll show the core practical examples you need to understand.

First thing: in most cases, you will never need to work directly with Service Container. For beginners, it's enough to understand that Service Container is a Laravel internal mechanism that allows us to do certain class injections "auto-magically", that's it.

In other words, you kinda need to forget about "service container" and learn the practical examples of its usage, instead. So, let's get to them.

Simple Example: Form Request Class

Let me show you that you probably have already used the Service Container, without even realizing it. Take a look at this example:

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

See that StoreUserRequest as a type-hint in the method? It's a typical Form Request class. Notice that we don't initialize the instance of that class? Laravel does this for us, if we type-hint the class.

In other words, we don't need to do this manually inside the method:

1$request = new StoreUserRequest();

So this is done by Service Container, it "resolves" the instance of that class, and auto-creates the object for us.

Another Typical Example: Controller Method Injection

We often want to use external classes in our Controllers. In my course about Laravel project structure I've discussed various classes to be used: Services, Actions, etc. Let's take Services as an example.

Question: how to initialize a Service class, to use it inside our Controller?

The most straightforward way:

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

But what if I told you that you don't need to initialize the service with new UserService()? And maybe you would guess how exactly Service Container could help us?

The answer is this:

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

Yes, we just add the class that we want to use inside the method, with type-hinting it, and Laravel will automatically create its variable to be used inside the method.

And you can do that in any method in your Controllers.

Does It Work Only For Methods? What About Constructors?

I'm glad you asked. Quite often, you need to use the class in multiple methods of the Controller.

So, inconvenient way:

1public function store(StoreUserRequest $request, UserService $userService) {
2 $userService->create($request->validated());
5public function update(User $user, UpdateUserRequest $request, UserService $userService) {
6 $userService->update($user, $request->validated());

Can we initialize the UserService for the whole Controller? Sure!

1public function __construct(public UserService $userService)
5public function store(StoreUserRequest $request) {
6 $this->userService->create($request->validated());
9public function update(User $user, UpdateUserRequest $request) {
10 $this->userService->update($user, $request->validated());

Notice: we're using PHP 8 constructor property promotion here, that's why constructor is empty.

Does It Work Only In Controllers?

No. According to the official documentation:

"You may type-hint the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, middleware, and more. Additionally, you may type-hint dependencies in the handle method of queued jobs."

Not sure exactly what that "and more" means, but you can try in any other Laravel class and see if it works.

Now, if you have your own custom PHP class and try to use this "trick", it wouldn't work, because Laravel wouldn't know about it.

For example, if you have a PHP Service class:

1class UserService {
3 public function __construct(SomeOtherService $someService) {}

That wouldn't work.

Advanced Level: Manual Binding and More

Basically, the above information is enough for beginners to know, on a practical level. You don't necessarily need to know how Service Container works under the hood, or how to bind/resolve the dependant classes in more complex cases.

But if you do want to find out about that... you can, of course, read the full page of the official documentation.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month

Written by

You might also like