What is the concept of Service Container in Laravel?
The Service Container in Laravel is a Dependency Injection Container and a Registry for the application
The advantages of using a Service Container over creating manually your objects are:
Ability to manage class dependencies on object creation
You define how a object should be created in one point of the application (the binding) and every time you need to create a new instance, you just ask it to the service container, and it will create it for you, along with the required dependencies
For example, instead of creating objects manually with the new
keyword:
//every time we need YourClass we should pass the dependency manually
$instance = new YourClass($dependency);
you can register a binding on the Service Container:
//add a binding for the class YourClass
App::bind( YourClass::class, function()
{
//do some preliminary work: create the needed dependencies
$dependency = new DepClass( config('some.value') );
//create and return the object with his dependencies
return new YourClass( $dependency );
});
and create an instance through the service container with:
//no need to create the YourClass dependencies, the SC will do that for us!
$instance = App::make( YourClass::class );
Binding of interfaces to concrete classes
With Laravel automatic dependency injection, when an interface is required in some part of the app (i.e. in a controller's constructor), a concrete class is instantiated automatically by the Service Container. Changing the concrete class on the binding, will change the concrete objects instantiated through all your app:
//everityme a UserRepositoryInterface is requested, create an EloquentUserRepository
App::bind( UserRepositoryInterface::class, EloquentUserRepository::class );
//from now on, create a TestUserRepository
App::bind( UserRepositoryInterface::class, TestUserRepository::class );
Using the Service Container as a Registry
You can create and store unique object instances on the container and get them back later: using the App::instance
method to make the binding, and thus using the container as a Registry.
// Create an instance.
$kevin = new User('Kevin');
// Bind it to the service container.
App::instance('the-user', $kevin);
// ...somewhere and/or in another class...
// Get back the instance
$kevin = App::make('the-user');
As a final note, essentially the Service Container -is- the Application
object: it extends the Container
class, getting all the container's funtionalities
Why use service container instead of new class
The purpose of Dependency Injection, which is achieved via Laravels IoC container (service container
), is to separate the creation and use of objects. So I would argue that having app(Employee::class);
is no better than new Employee
or Employee::create()
. IoC is more than just registering objects with the container and pulling them out when you need them.
A practical example for this might be where you have a class which transmits SMS
messages.
class Sms
{
private $smsProvider;
public function send()
{
$this->smsProvider->send();
}
}
So your SmsSender
class requires a smsProvider
to function. Rather than creating a new
instance of the SMS
provider in Sms
class, you would inject the provider into the class (usually the constructor in such examples) and make use of it that way. If you wanted to make it even more flexible, you would define an interface for SMS
providers and then allow the service container to inject the correct concrete class from your IoC mappings.
class Sms
{
private $smsProvider;
public __construct(ISmsProvider $smsProvider)
{
$this->smsProvider = $smsProvider;
}
public function send()
{
$this->smsProvider->send();
}
}
class SmsTwillio implements ISmsProvider
{
}
class SmsNexmo implements ISmsProvider
{
}
You would then define mappings in the service container to bind references to ISmsProvider
to a concrete implementation such as SmsTwillio
or SmsNexmo
.
Using your example, you might define a PayrollService
:
class PayrollService
{
public function process($employees, $start, $end = null)
{
foreach ($employees as $employee) {
$salary = $this->calculateNetSalary($employee);
}
}
private function calculateNetSalary(Employee $employee)
{
}
}
class ProcessPayrollController extends ProcessPayrollController
{
private $payrollService;
public __constructor(PayrollService $PayrollService)
{
$this->payrollService = $payrollService;
}
public function __invoke()
{
$result = $this->payrollService->process(Employee::all(), '2021-06-01');
}
}
I don't think your Payroll
class needs Leave
or Timesheet
. I would define functions
or scopes
on your Employee
class which returns that data:
$employee->daysUnpaidLeave('2021-06-01');
$employee->hoursLate('2021-06-01');
Where the dates are the start
date to calculate from until today, or provide an optional end
date as a second argument.
You could go even deeper down the rabbit hole and look at other creational design patterns for creating objects at runtime, however, design patterns can be quickly abused and add complexity rather than reduce it, so keep it simple.
The Registry
in OpenCart is a similar principal. In that example $registry->get('language');
will always return the same instance of Language
, so yes it would be a singleton.
Your Payroll
could be a singleton as you don't need multiple instances of it as it is simply processing data you provide to it.
Where to find Service Containers in a Laravel project?
Service container is a core component of Laravel framework that is ready for you to use as it is, you are not supposed to create your own service containers like you do, for example, with service providers.
You can imagine service container being an associative array where you can store dependencies (services) and logic of how to resolve them. Then you can use service container to give you what you need based on what is there using provided logic.
It would be easier to imagine that service container is a black box that is always available. Your app at first registers (puts) certain rules in there (for example, if someone wants an object that implements PriceCalculator
interface then give him object of a class MyPriceCalculator
). It is done in register()
method of your service providers:
$this->app->bind('App\Contracts\PriceCalculator', 'App\Shop\MyPriceCalculator');
Then this black box is always available for you, so if you ever need PriceCalculator
object (for example, somewhere in your cart controller to calculate price of some order) you can now instead of doing:
$calculator = new \App\Shop\MyPriceCalculator;
Ask service container to make you a proper one:
$calculator = app()->make('App\Contracts\PriceCalculator');
Note how we are asking service container to give us implementation of an interface and will in turn give us new App\Shop\MyPriceCalculator
object because that is how we defined (registered) App\Contracts\PriceCalculator
service earlier.
Using service container is a great way to manage all dependencies of your application since your code will be working with abstractions and how those abstractions are resolved will be always defined in one place (which means it's easier to maintain if you want to change something later on).
If you are new to Laravel I would recommend to skip service containers for now since it's a little bit more advanced topic and you are required to have a better understanding of dependency injection pattern to fully grasp it and use properly.
You can read official documentation here.
Laravel What is the use of service providers for laravel
First of all, Laravel uses service container and service providers, not server container or server provider :)
Here are some benefits of using dependencies injection (DI):
Simplify the object creation
Because your Test
class constructor is quite simple, you don't see the benefit of dependencies injection. Think about a class like this:
class Complex {
public function __construct(
FooService $fooService,
BarService $barService,
int $configValue
) {
}
}
Without DI, you have to get (or create) instances of $fooService
and $barService
, retrieve the value of $configValue
from the configuration files every time you want a new instance of the Complex
class.
With DI, you tell the service container how to create the Complex
instance once, then the container can give the correct instance for you with one call (e.g. $container->make(Complex::class)
)
Manage the couplings between your classes
Continue with the previous example. What happens if the FooService
and BarService
depends on other classes, too?
Without DI, you have to create instances of the dependent objects (and hope that they do not depends on other classes). This usually ends with multiple instances of one class created, a waste of codes and computer memory.
With DI, all dependent objects are created by the container (you have to register those classes with the container before). The container also manages to keep only one instance of each class if you want, which save the amount of code as well as the amount of memory used by your program.
Only use one instance of your classes when registering with singleton
To keep only one instance of the class in the whole life of the current request, you can register your class creation process with singleton
method instead of bind
the meaning of dependencies in composer and laravel service container
Composer deals with making copies of libraries available within the project at all. It ensures the libraries you have denoted as required are present in the vendor folder within your project. It doesn't know anything about you project or how these libraries are used, or if they are at all. Composer deals with which libraries your project depends on and makes sure they are available.
The Laravel service container deals with instantiating instances of classes at run time.
If you have a parameter to a constructor with a specific class type-hint, the service container is the piece which resolves that for you. e.g.
public function __construct(User $user)
{
$user;
}
The Laravel service container deals with run time dependencies and resolves classes in order to instantiates objects as needed.
Related Topics
Creating a Very Simple 1 Username/Password Login in PHP
Laravel 5.1 Unknown Database Type Enum Requested
Sort Array by Length and Then Alphabetically
Have Gd Get Image from Binary String
HTML Table Using MySQLi and PHP
Efficient PHP Auto-Loading and Naming Strategies
Email PDF Attachment with PHP Using Fpdf
Laravel 5.2 - Pluck() Method Returns Array
How to Export and Import MySQL Database with Its Data Using PHP Script
Avoiding Recursion with Doctrine Entities and Jmsserializer
How to Enable Shell_Exec and Exec on PHP
How to Format an Utc Date to Use the Z (Zulu) Zone Designator in PHP
How to Create a Logfile in PHP
How to Display All the Images Stored Inside a Database
Symfony2 Collection of Entities - How to Add/Remove Association with Existing Entities
PHP Get Actual Maximum Upload Size
How to Install Laravel Without Using Composer
Minifying Final HTML Output Using Regular Expressions with Codeigniter