Article from: learnku.com/laravel/t/2…
As developers, we are always trying to find new ways to write well-designed and robust code by using design patterns and experimenting with new robust frameworks. In this article, we’ll explore the dependency injection design pattern through Laravel’s IoC component and see how it can improve our design.
Dependency injection
Dependency injection, a term coined by Martin Fowler, is the act of injecting components into an application. As Ward Cunningham put it:
Dependency injection is a key element in agile architectures.
Let’s look at an example:
class UserProvider{
protected $connection;
public function __construct() {$this->connection = new Connection;
}
public function retrieveByCredentials( array $credentials) {$user = $this->connection
->where( 'email'.$credentials['email'])
->where( 'password'.$credentials['password'])
->first();
return $user; }}Copy the code
If you want to test or maintain this class, you must access an instance of the database to perform some queries. To avoid having to do this, you can decouple this class from other classes, and you have one of three options to inject the Connection class without using it directly.
When injecting a component into a class, you can use one of three options:
Constructor injection
class UserProvider{
protected $connection;
public function __construct( Connection $con) {$this->connection = $con; }...Copy the code
Setter method injection
Similarly, we can inject dependencies using Setter methods:
class UserProvider{
protected $connection;
public function __construct(){
...
}
public function setConnection( Connection $con) {$this->connection = $con; }...Copy the code
Interface injection
interface ConnectionInjector{
public function injectConnection( Connection $con );
}
class UserProvider implements ConnectionInjector{
protected $connection;
public function __construct(){
...
}
public function injectConnection( Connection $con) {$this->connection = $con; }}Copy the code
When a class implements our interface, we define injectConnection methods to resolve dependencies.
advantage
Now, when testing our class, we can simulate the dependent class and pass it as a parameter. Each class must focus on a specific task and should not be concerned with resolving their dependencies. This way, you’ll have a more focused and maintainable application.
If you want to learn more about DI, Alejandro Gervassio has covered it extensively and professionally in this series, so be sure to read these articles. So what is IoC? IoC (Inversion of Control) does not require dependency injection, but it can help you manage dependencies effectively.
Inversion of control
Ioc is a simple component that makes it easier to resolve dependencies. You can describe objects as containers and inject dependencies automatically every time a class is parsed.
Laravel Ioc
When you request an object, Laravel Ioc has a special way of resolving dependencies:
We’ll use a simple example and improve it in this article. The SimpleAuth class relies on FileSessionStorage, so our code might look like this:
class FileSessionStorage{
public function __construct(){
session_start();
}
public function get( $key) {return $_SESSION[$key];
}
public function set( $key.$value) {$_SESSION[$key] = $value;
}
}
class SimpleAuth{
protected $session;
public function __construct() {$this->session = new FileSessionStorage; } // Create a SimpleAuth$auth = new SimpleAuth();
Copy the code
This is a classic approach, so let’s start with constructor injection.
class SimpleAuth{
protected $session;
public function __construct( FileSessionStorage $session) {$this->session = $session; }}Copy the code
Now we create an object:
$auth = new SimpleAuth( new FileSessionStorage() );
Copy the code
Now I want to use Laravel Ioc to manage everything.
Because the Application class inherits from the Container class, you can access the Container through the App facade.
App::bind( 'FileSessionStorage'.function() {return new FileSessionStorage;
});
Copy the code
The bind method takes the first argument to the unique ID to bind to the container, and the second argument is a callback function that is executed whenever the FileSessionStorage class is executed. We can also pass a string that represents the class name, as shown below.
Note: If you look at the Laravel package, you’ll see that bindings are sometimes grouped, such as (View, view.finder…). .
Assuming we convert session storage to Mysql storage, our class should look something like:
class MysqlSessionStorage{
public function __construct() {/ /... } publicfunction get($key{/ /do something
}
public function set( $key.$value{/ /do something
}
}
Copy the code
Now that we’ve changed the dependency, we also need to change the SimpleAuth constructor and bind the new object to the container!
High-level modules should not depend on low-level modules; both should depend on abstract objects. Abstraction should not depend on details, details should depend on abstractions.
Robert C. Martin
Our SimpleAuth class should not care about how our storage is done, but rather it should focus on consuming services.
Therefore, we can implement our storage abstractly:
interface SessionStorage{
public function get( $key );
public function set( $key.$value );
}
Copy the code
So we can implement and request an instance of the SessionStorage interface:
class FileSessionStorage implements SessionStorage{
public function __construct() {/ /... } publicfunction get( $key{/ /... } publicfunction set( $key.$value{/ /... } } class MysqlSessionStorage implements SessionStorage{ publicfunction __construct() {/ /... } publicfunction get( $key{/ /... } publicfunction set( $key.$value{/ /... } } class SimpleAuth{ protected$session;
public function __construct( SessionStorage $session) {$this->session = $session; }}Copy the code
If we use the App: : make (‘ SimpleAuth) through analytical SimpleAuth class container, the container will be thrown BindingResolutionException, trying to from a binding resolution after class, return to the reflection method and resolve all dependencies.
Uncaught exception 'Illuminate\Container\BindingResolutionException' with message 'Target [SessionStorage] is not instantiable.'
Copy the code
The container is attempting to instantiate the interface. We can make a concrete binding for this interface.
App:bind( 'SessionStorage'.'MysqlSessionStorage' );
Copy the code
Now every time we try to resolve the interface from the container, we get an instance of MysqlSessionStorage. If we want to switch our storage service, we just change this binding.
Note: If you want to check if a class is already bound in the container, you can use App::bound(‘ClassName’), or you can use App::bindIf(‘ClassName’) to register a binding that has not yet been registered.
Laravel Ioc also provides App:: Singleton (‘ClassName’, ‘resolver’) to handle singleton bindings. You can also create a singleton binding using App::instance(‘ClassName’, ‘instance’). A ReflectionException is thrown if the container cannot resolve the dependency, but we can use the App::resolvingAny(Closure) method to resolve any specified type in the form of a callback function.
Note: If you have registered a resolvingAny method for a type, the resolvingAny method will still be called, but it will directly return the value returned by bind.
Tips:
- Where do these bindings go: if it’s just a small application you can write them in a global start file
global/start.php
But it’s necessary if the project gets bigger and biggerService Provider 。 - Testing: Consider using it when you need a quick and easy test
php artisan tinker
It is very powerful and can help you improve your Laravel testing process. - Reflection API: PHP’s Reflection API is very powerful. If you want to go deep into Laravel Ioc you need to be familiar with the Reflection API. Check out this tutorial for more information.
The last
As always, the best way to learn or learn something is to look at the source code. Laravel Ioc is just a file and it won’t take you too long to complete all the features. Do you want to know more about Laravel Ioc or Ioc in general? Then tell us!
Article from: learnku.com/laravel/t/2… More articles: learnku.com/laravel/c/t…