Containers and dependency injection



Container and dependency injection (container)

Dependency injection is implemented through the container, which can realize Automatic introduction of the referenced class, and automatic loading of the dependent objects of the class

Dependency injection refers to the automatic injection of class dependencies through the constructor:

<?php
namespace app\index\controller;

use app\index\model\User;

class Index
{
    protected $user;

    // 通过依赖注入方式,实现User实例的自动注入到当前对象中
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function hello()
    {
        return 'Hello,' . $this->user->name . '!';
    }
}

Object parameter support for dependency injection Multiple, and the order is irrelevant.

Binding

Dependency injected classes are uniformly managed by the container, and in most cases are automatically bound and instantiated. However, you can manually bind the class to the container at any time (usually in the register method of the service class), and multiple binding methods are supported.

Bind class identification

You can bind an identification (unique) to an existing class library for quick calling.

// 绑定类库标识
$this->app->bind('cache', 'think\Cache');

Or use the helper function

// 绑定类库标识
bind('cache', 'think\Cache');

The bound class identifier can be defined by yourself (as long as there is no conflict).

Binding closure

You can bind a closure to the container

bind('sayHello', function ($name) {
    return 'hello,' . $name;
});

Binding instance

You can also directly bind an instance of a class

$cache = new think\Cache;
// 绑定类实例
bind('cache', $cache);

Bind to the interface implementation

For dependency injection using interface classes, we need Tell the system which specific interface implementation class to use for injection. This use can bind a certain class to the interface

// 绑定think\LoggerInterface接口实现到think\Log
bind('think\LoggerInterface','think\Log');

Use the interface as the type of dependency injection

<?php
namespace app\index\controller;

use think\LoggerInterface;

class Index
{
    public function hello(LoggerInterface $log)
    {
    	$log->record('hello,world!');
    }	
}

Batch binding Determined

In the actual application development process, manual binding is not required. We only need to define the provider.php file under the application directory (returning an array), and the system will automatically bind the class library to the container in batches. middle.

return [
    'route'      => \think\Route::class,
    'session'    => \think\Session::class,
    'url'        => \think\Url::class,
];

The binding identifier is case-sensitive when called. The system has already built-in binding core common class libraries, so there is no need to bind them repeatedly.

The system’s built-in class libraries bound to the container include

##think\Langlang##think\Logthink\Middlewarethink\Requestthink\Responsethink\Filesystemthink\Route think\Sessionthink\Validatethink\View

Analysis

Use the app helper function to make class analysis calls in the container. For the bound class identifier, it will be automatically and quickly instantiated

$cache = app('cache');

With parameters Instantiation call

$cache = app('cache',['file']);

For unbound classes, you can also directly parse

$arrayItem = app('org\utils\ArrayItem');

The identifiers of the call and the binding must be consistent (including case)

In the container Classes that have already been called will automatically use singletons unless you force re-instantiation using the following method.

// 每次调用都会重新实例化
$cache = app('cache', [], true);

Objectized call

Use the app helper function to obtain the object instance in the container (supports dependency injection).

$app = app();
// 判断对象实例是否存在
isset($app->cache);

// 注册容器对象实例
$app->cache = think\Cache::class;

// 获取容器中的对象实例
$cache = $app->cache;

In other words, you can use the app() method anywhere to call any class in the container, but in most cases, we recommend using dependency injection.

// 调用配置类
app()->config->get('app_name');
// 调用session类
app()->session->get('user_name');

Automatic injection

Containers are mainly used for dependency injection. Dependency injection will first check whether the object instance has been registered in the container. If not, it will automatically Instantiate and then automatically inject, for example:

We can bind the model object instance to the route

Route::get('user/:id','index/Index/hello')
	->model('\app\index\model\User');

Then automatically inject the User model in the operation method

<?php
namespace app\index\controller;

use app\index\model\User;

class Index
{

    public function hello(User $user)
    {
        return 'Hello,'.$user->name;
    }

}

Customized instantiation

Object instantiation in the container supports customization. You can add the __make method definition to the object you need to dependency injection, for example:

If If you want the User model class to use custom instantiation during dependency injection, you can use the following method.

<?php
namespace app\index\model;

use think\Model;
use think\db\Query;

class User extends Model
{
	public static function __make(Query $query)
    {
    	return (new self())->setQuery($query);
    }
}

Container object callback mechanism

After the object in the container is instantiated, it supports a callback mechanism, which can be used to implement related functions such as annotation functions.

You can register a global callback through the resolving method

Container::getInstance()->resolving(function($instance,$container) {
    // ...
});

The callback method supports two parameters, the first parameter is the container object instance, and the second parameter is the container instance itself.

Or separately register a callback for a container object

Container::getInstance()->resolving(\think\Cache::class,function($instance,$container) {
    // ...
});


System class libraryContainer binding identifier
think\Appapp
think\Cachecache
think\Configconfig
think\Cookiecookie
think\Consoleconsole
think\Dbdb
think\Debugdebug
think \Envenv
think\Eventevent
think\Httphttp
log
middleware
request
response
filesystem
route
session
validate
view