Using Service Container to create Objects in Laravel
Saurabh Mahajan
Posted on April 16, 2022
Recently I tweeted about using Service Container to create an Object instead of using the new
Keyword and it led to a lot of questions.
In this article, we will see how to create objects using Service Container and some of its benefits.
Let's say we have a Transistor
class as follows:
namespace App\Services;
class Transistor {
public function __construct()
{
}
.
.
.
}
Now, if we want to use this Class in the index method of our Controller, we would do something like below:
public function index()
{
$transistor = new Transistor();
.
.
}
However, the way Laravel works under the hood, we can simply inject our Transistor Class like below:
public function index(Transistor $transistor)
{
//$transistor object will be available here.
.
.
}
Laravel is automatically able to resolve the Transistor Class and able to inject it into our method (This is also known as Dependency Injection).
In fact, you might have been using this Laravel Feature even without knowing it. Ever wondered how Request
Class gets injected into your Controller Methods.
public function store(Request $request)
{
.
.
}
Now, currently our Transistor Class has, what we call, Zero Configuration so Laravel is able to resolve the Class on its own. Now let us say that our Transistor Class expected a parameter via Constructor as follows:
namespace App\Services;
class Transistor {
public $key;
public function __construct($key)
{
$this->key = $key;
}
.
.
.
}
Now since our Transistor Class expects a parameter, Laravel would not be able to resolve the Class on its own. We will need to tell Laravel how to resolve this Class. We can do so in AppServiceProvider
as follows:
$this->app->bind(Transistor::class, function () {
return new Transistor(config('settings.key'));
});
So now every time, we ask for the Transistor Class to be injected, Laravel will look into the Service Provider and inject the Class as we have defined.
Laravel Service Container supports many other type of Binding, which are beyond the scope of this Article. You can check them in the Documentation.
Now, some of the benefits of using the Service Container to resolve your Classes are:
Controller is no longer responsible for creating the Object. We just inject the Object into the Controller and Controller is only responsible for calling the methods related to Transistor Class. This removes a lot of noise and helps to keep our Controller Clean.
If the implementation of our Transistor class changes in the future, let's say our Transistor Class requires another parameter to be passed via constructor, we only need to make changes at one single location. Without Service Container, we will have to make changes at every file where Transistor Class is being used.
Using Service Container makes it very easy to Mock the Transistor Class using Tests.
$mock = $this->mock(Transistor::class, function (MockInterface $mock) {
$mock->shouldReceive('fetchStations')->once();
});
This is even more useful when our Transistor Class is hitting a Third Party API and we want to avoid hitting the API during our Tests so as to avoid Rate Limit as well as make our Tests faster.
Without using Service Container, it would not be easy to Mock our Transistor Class.
In conclusion, if you are using new
to create an Object in Laravel, there is a probably a better way.
Posted on April 16, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.