Introduction to the advantages of using laravel service container

Time:2022-7-11

If the core of the laravel framework is anything, it is undoubtedly a service container. Understanding the concept of service container is too important for us to use laravel. It should be said that whether we understand the concept of service container is an important condition to distinguish whether we are starting laravel or not. Because the whole framework is built on the basis of service container.

The laravel service container is like a highly automated factory. You need to customize the model and use specific interfaces to manufacture the things you need.

Because the service container is used, most objects in laravel are instantiated in this way:

1
2
3
$obj1 = $container->make(‘class1’, ‘class2’);

$obj2 = $container->make(‘class3’, ‘class4’);

However, without using the service container, the following methods can also be achieved:

1
2
3
$obj1 = new class1(new class2());

$obj2 = new class3(new class4());

So what are the advantages of using service containers? Here are some specific examples to analyze its advantages:

Example 1: send email

We encapsulate the function of sending mail into a class. When we need to use it, we instantiate and call the sending method.

The following are common ways not to use the laravel service container:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**

*Send mail service class

*/

class EmailService{

public function send(){

//Todo email sending method

}

}

//If you want to send an email anywhere, we will copy the following two lines of code

$emailService = new EmailService();

$emailService->send();

After using the laravel service container:

1
2
3
4
5
6
7
8
9
10
11
$this->app->bind(’emailService’, function ($app) {

return new EmailService();

});

//If you want to send an email anywhere, we will copy the following two lines of code

$emailService = app(’emailService’);

$emailService->send();

This makes our code more concise, and because of the middle tier, the flexibility is improved (decoupling), so it is more convenient to test (when testing, we can forge classes to replace emailservice classes) or optimize emailservice classes.

1
2
3
4
5
6
7
//Just change this place

$this->app->bind(’emailService’, function ($app) {

return new SupperEmailService();

});

We don’t need to touch other parts of the call at all. If we don’t have this binding operation, we have to make changes in every place where the mail service is used.

1
2
3
4
5
//Every place you use the eamilserice class needs to be changed

$emailService = new SupperEmailService();

$emailService->send();

Example 2: implement the singleton mode

In the above example, for performance reasons, you need the suppleeamilservice class to implement the singleton mode, so without using the laravel service container, you change the suppleemailservice class as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class SupperEamilService{

//Create a static private variable to save this kind of object

static private $instance;

//Prevent direct creation of objects

private function __construct(){

}

//Prevent cloning objects

private function __clone(){

}

static public function getInstance(){

//Determine whether $instance is an object of uni

//Create if not

if (!self::$instance instanceof self) {

self::$instance = new self();

}

return self::$instance;

}

//Send mail method

public function send(){

}

}

In addition, since the constructor of suppleeamilservice class is private now, the object cannot be instantiated through the new keyword, so it should be changed to this in every instantiation of suppleemailservice class:

1
2
3
$emailService=SupperEmailService::getInstance();

$emailService->send();

The laravel service container naturally supports singletons. The following is the implementation of laravel:

1
2
3
4
5
6
7
//Just change bind to singleton

$this->app->singleton(’emailService’, function ($app) {

return new SupperEmailService();

});

To realize the singleton, you only need to change one line of code, change the original bind method to singleton, and the singleton is taken out through the container, which is really very convenient.

Example 3: tourists travel

This example assumes that a traveler can travel to Tibet by train or leg.

Do not use the laravel service container:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php

interface TrafficTool

{

public function go();

}

class Train implements TrafficTool

{

public function go()

{

echo “train….”;

}

}

class Leg implements TrafficTool

{

public function go()

{

echo “leg..”;

}

}

class Traveller

{

/**

* @var Leg|null|Train

*Travel tools

*/

protected $_trafficTool;

public function __construct(TrafficTool $trafficTool)

{

$this->\_trafficTool = $trafficTool;

}

public function visitTibet()

{

$this->_trafficTool->go();

}

}

When travelers travel by train, we usually write this:

1
2
3
4
5
6
7
<?php

$train = new Train();

$tra = new Traveller($train);

$tra->visitTibet();

In fact, this way of writing is very good, because the dependence on travel tools has been transferred to the outside through the interface. However, when using new to instantiate objects, dependencies will still occur For example, traffictool above), which means that we must have a $traffictool before creating a traveller, that is, traveller depends on traffictool When new is used to instantiate traveler, there is a coupling between traveler and traffictool In this way, the two components cannot be separated.

Now let’s look at how to use the laravel service container:

Bind classes in the service container

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

namespace App\Providers;

use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider

{

public function register()

{

//Bind classes in the service container

$this->app->bind( ‘TrafficTool’, ‘Train’);

$this->app->bind(‘Traveller’, ‘Traveller’);

}

}

Instantiate object
1
2
3
4
5
6
7
<?php

//Instantiate object

$tra = app()->make(‘Traveller’);

$tra->visitTibet();

When we use the service container to obtain the object of travel class, the container will automatically inject the parameters required by the object. Before that, I only need to bind specific classes, which reflects the real automation and completely decouples the travel class from the travel tool class. When we need to change the way we travel, we just need to change the binding.