Understanding the Laravel Service Container

Percy Mamedy
dotdev
Published in
5 min readSep 12, 2016

--

Learning how to build an application with Laravel is not just about learning to use the different classes and components within the framework, it is not about remembering all artisan commands or remembering all helper functions (we have Google for that). Learning to code with Laravel is learning the philosophy of Laravel, its elegance and its beautiful syntax. I personally feel it is an art and a craft (its not a coincidence that Laravel developers are sometimes referred to as Web artisans). This is true for any other framework as well.

A major part of Laravel’s philosophy is the Service Container or IoC container. As a Laravel developer, understanding and using the Service Container properly is a crucial part in mastering your craft, as it is the core of any Laravel application.

The Basics

Basically the IoC Container is just an ordinary PHP class, but I like to think of it as my “Bag of tricks”. This “Bag” is where we will place or “Bind” everything we need to run a Laravel application smoothly, from interfaces implementations to directories paths and so on. Yes you can place pretty much anything you want in it !… Hence, the term “Bag of tricks”.

Now, since we have a single Object that contains all of our various bindings, it is very easy to retrieve them back or “resolve” them at any point in our code.

Binding and Resolution

Now let’s imagine we have a certain Class FooService that provides some particular service.

<?phpnamespace App\Services;class FooService
{
public function __construct()
{
...
}
public function doSomething()
{
// Code for Something.
}
}

If we wanted to use the class’ doSomething method we would probably end up doing something like :

$fooService = new \App\Services\FooService();
$fooService->doSomething();

This is great, but the thing that is bugging me here is the ‘new’ keyword, I mean don’t get me wrong it’s great but maybe we could be more elegant here (remember coding with Laravel is coding with elegance).

How do we bind ?

Binding is as simple as this line of code

$this->app->bind('FooService', \App\Services\FooService::class);

Essentially we are telling Laravel: “Hey store this object in your bag of tricks and label it as FooService”.

Of course there are other ways to bind services all depending on the situation and the way services will be used but you get the basic idea. For a complete reference on binding, check out Laravel’s doc on the service container.

Remember to always bind your services within the register method of your service providers.

How do we resolve ?

After our service is bound in the container we can now retrieve or “resolve” it from anywhere within our app.

// Using IoC we could end up with this
$fooService = app()->make('FooService');
$fooService->doSomething();
// Eventually this, basically one line of code
app()->make('FooService')->doSomething();

Here we are just telling Laravel: “Hey remember that FooService I told you to keep, well I need it now so just give it back to me.”

Did you notice how, using the IoC to create services makes the code much cleaner, elegant and also readable. That’s the beauty of Laravel, and as an added bonus your code is now easier to test since you can now replace the FooService with a mocked object while testing (I am guessing you are familiar with Mocking objects in tests).

Interface binding with the IoC

An interface in Object Oriented Programming is a way to create classes that must follow some kind of Blueprint or Contract. This helps other developers working with you, create code that matches constraints set within your interface. This enforces them to return a specific datatype and pass fixed set of parameters to their methods; even though implementation of their methods might be different. This way you can rest assured that different implementations of the same interface will work the same way.

With the IoC of Laravel we can bind a specific implementation of an interface to it, in this way when ever we resolve this interface we will end up with the concrete class that is bound to it.

$this->app->bind(FooInterface::class, FooClass::class);

Hence, when FooInterface is resolved, Laravel is smart enough to give us an instance of FooClass.

Now imagine we have written a better implementation of FooInterface called BarClass and would like to use that now instead of FooClass. Then all we would need to change would be :

$this->app->bind(FooInterface::class, BarClass::class);

Our code will still work the same way because we know that BarClass will respect our interface and if ever BarClass is not performing as expected would could just change it back to FooClass. This is a great way to upgrade an application’s code without too many regressions.

Resolving dependencies

We know that Laravel can resolve a service or interface that we bound to the IoC, but it can do much more than that. In fact it can resolve these services’ dependencies for us without us having to write a single line of code.

Imagine we have the following services classes in our App.

As we can see here FooService requires an instance of BarService to be able to instantiate. How would we be able to bind this in the container such that whenever Laravel gives us an instance of FooService it will also give us an instance of BarService ?

Well, you might think the solution would be to do this:

$this->app->bind('Foo', new FooService(new BarService));

Technically that would work, but really we don’t have to. Laravel automatically figures it out for us by using a powerful feature of PHP called reflection. Hence you would do you binding as usual:

$this->app->bind('Foo', FooService::class);

Now when we resolve Foo, behind the scenes Laravel will Look for FooService , sees it needs an instance of BarService ; hence Laravel will instantiate BarService and supply it to the constructor of FooService and give us the complete built up instance without us having to write a single line of code. Pretty crazy stuff !!

Furthermore, this process will keep repeating itself for all dependencies, so if BarService had some dependencies these would also get resolved.

Final words

There are many great things to be discussed and to learn about the IoC of Laravel. I hope that this little introduction has shed some light and help you get some insights about the container.

I do encourage you to learn more about it by reading the docs.

Thank you for reading.

--

--