컨테이너 및 종속성 주입



컨테이너와 종속성 주입(컨테이너)

종속성 주입은 컨테이너를 통해 구현되는데, 이는 참조된 클래스를 자동으로 도입하고 클래스의 종속 개체를 자동으로 로드할 수 있습니다.

종속성 주입 종속성을 의미합니다. 클래스의 클래스는 생성자를 통해 자동으로 주입됩니다.

<?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 . '!';
    }
}

종속성 주입의 객체 매개변수는 여러 객체를 지원하며 순서는 이와 관련이 없습니다.

Binding

종속성이 주입된 클래스는 컨테이너에 의해 균일하게 관리되며 대부분의 경우 자동으로 바인딩되고 인스턴스화됩니다. 그러나 언제든지 클래스를 컨테이너에 수동으로 바인딩할 수 있으며(일반적으로 서비스 클래스의 등록 메서드에서) 여러 바인딩 메서드가 지원됩니다.

클래스 식별자 바인딩

빠른 호출을 위해 식별자(고유)를 기존 클래스 라이브러리에 바인딩할 수 있습니다.

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

또는 도우미 함수

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

를 사용하여 바인딩된 클래스 식별자를 직접 정의하세요(충돌이 없는 한).

바인드 클로저

클로저를 컨테이너에 바인딩할 수 있습니다

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

인스턴스 바인딩

클래스의 인스턴스를 직접 바인딩할 수도 있습니다

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

인터페이스 구현에 바인딩

종속성의 경우 인터페이스 클래스를 사용하여 주입하려면 주입에 사용할 특정 인터페이스 구현 클래스를 시스템에 알려야 합니다. 이렇게 하면 특정 클래스를 인터페이스에 바인딩할 수 있습니다

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

인터페이스를 종속성 주입 유형으로 사용

<?php
namespace app\index\controller;

use think\LoggerInterface;

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

일괄 바인딩

실제 애플리케이션 개발 프로세스에서는 수동 바인딩이 필요하지 않습니다. 애플리케이션 디렉터리 아래에 공급자.php 파일을 정의하기만 하면(배열 반환) 시스템이 클래스 라이브러리를 일괄적으로 컨테이너에 자동으로 바인딩합니다.

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

바인딩 식별자는 호출 시 대소문자를 구분합니다. 시스템에는 핵심 공통 클래스 라이브러리의 바인딩이 내장되어 있으므로 이를 반복적으로 바인딩할 필요가 없습니다.

컨테이너에 바인딩된 시스템의 내장 클래스 라이브러리는 다음과 같습니다.

시스템 클래스 라이브러리 컨테이너 바인딩 ID
thinkAppapp
thinkCachecache
thinkConfig config
thinkCookie cookie
thinkConsoleconsole
thinkDbdb
thinkDebugdebug
thinkEnvenv
thinkEvent event
thinkH ttphttp
thinkLanglang
thinkLog log
thinkMiddlewaremiddleware
thinkRequestrequest
thinkResponse 응답
thinkFile 시스템filesystem
thinkRoute route
thinkSession session
thinkValidatevalidate
thinkViewview

파싱

앱 도우미 기능을 사용하여 컨테이너에서 클래스 구문 분석 호출을 수행하세요. 바인딩된 클래스 식별자의 경우 자동으로 빠르게 인스턴스화됩니다.

$cache = app('cache');

매개변수가 있는 인스턴스화 호출

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

언바운드 클래스의 경우에도 파싱 가능 직접

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

호출 및 바인딩 식별자는 일관되어야 합니다(대문자 및 소문자 포함)

다음 방법을 사용하여 강제로 다시 인스턴스화하지 않는 한 컨테이너에서 호출된 클래스는 자동으로 싱글톤을 사용합니다.

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

객관화된 호출

앱 도우미 기능을 사용하여 컨테이너의 개체 인스턴스를 가져옵니다(종속성 주입 지원).

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

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

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

즉, app() 메서드를 어디서나 사용하여 컨테이너의 모든 클래스를 호출할 수 있지만 대부분의 경우 종속성 주입을 사용하는 것이 좋습니다.

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

자동 주입

컨테이너는 주로 종속성 주입에 사용됩니다. 종속성 주입은 먼저 개체 인스턴스가 컨테이너에 등록되었는지 여부를 확인한 다음 자동으로 인스턴스화됩니다. :

라우트는 모델 객체 인스턴스를 바인딩하고

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

를 제공한 다음 작업 메서드에 사용자 모델을 자동으로 주입합니다.

<?php
namespace app\index\controller;

use app\index\model\User;

class Index
{

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

}

사용자 정의 인스턴스화

컨테이너의 객체 인스턴스화는 사용자 정의를 지원하고 다음에 추가될 수 있습니다. 종속성 주입이 필요한 개체 __make 메서드 정의(예:

사용자 모델 클래스가 종속성 주입 중에 사용자 정의 인스턴스화를 사용하도록 하려면 다음 메서드를 사용할 수 있습니다.)

<?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::getInstance()->resolving(function($instance,$container) {
    // ...
});

콜백 메서드는 두 개의 매개변수를 지원하며 첫 번째 매개변수는 컨테이너 개체 인스턴스이고 두 번째 매개변수는 컨테이너 인스턴스 자체입니다.

또는 특정 컨테이너 객체에 대한 콜백을 별도로 등록

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