国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Lumen框架“服務(wù)容器”源碼解析

ytwman / 737人閱讀

摘要:下邊是服務(wù)容器工作示意圖服務(wù)容器的產(chǎn)生框架中,服務(wù)容器是由中類完成的,該類實現(xiàn)了服務(wù)容器的核心功能。并不是框架中所有的類都能實現(xiàn)自動依賴注入的功能只有服務(wù)容器創(chuàng)建的類實例才能實現(xiàn)依賴自動注入。框架中的服務(wù)容器是全局的,不需要

1.服務(wù)容器

“服務(wù)容器”是Lumen框架整個系統(tǒng)功能調(diào)度配置的核心,它提供了整個框架運行過程中的一系列服務(wù)。“服務(wù)容器”就是提供服務(wù)(服務(wù)可以理解為系統(tǒng)運行中需要的東西,如:對象、文件路徑、系統(tǒng)配置等)的載體,在系統(tǒng)運行的過程中動態(tài)的為系統(tǒng)提供這些服務(wù)。下邊是服務(wù)容器工作示意圖:

1.1、服務(wù)容器的產(chǎn)生

Lumen框架中,服務(wù)容器是由illuminate/container/Container.php中Container類完成的,該類實現(xiàn)了服務(wù)容器的核心功能。laravel/lumen-framework/src/Application.php中Application類繼承了該類,實現(xiàn)了服務(wù)容器初始化配置和功能拓展。源碼中生成服務(wù)容器的代碼是在bootstrap/app.php中:

$app = new LaravelLumenApplication(
    dirname(__DIR__)
);

也就是Lumen框架在處理每一個請求的時候,都會首先為這個請求生成一個服務(wù)容器,用于容納請求處理需要的服務(wù)。

1.2、服務(wù)綁定

服務(wù)容器生成以后,就可以向其中添加服務(wù),服務(wù)綁定可以理解為一個服務(wù)和一個關(guān)鍵字綁定,看作鍵值對的形式就是:一個"key" 對應(yīng)一個服務(wù)。要綁定的服務(wù)不同,使用的容器中的綁定函數(shù)也不同,框架初始化時使用到的是回調(diào)函數(shù)服務(wù)綁定和實例對象服務(wù)綁定。回調(diào)函數(shù)綁定分兩種:一種是普通綁定,另外一種是單例綁定,通過bind()函數(shù)中的參數(shù)$shared進(jìn)行區(qū)分,項目代碼中的singleton()綁定單例就是bind()函數(shù)中$shared參數(shù)為true的情況。源碼如下:

 public function singleton($abstract, $concrete = null)
    {
        $this->bind($abstract, $concrete, true);
    }

單例綁定在整個Lumen生命周期中只會生成并使用一個實例對象。綁定一個實例對象到容器中使用的是instance()函數(shù),綁定之后生成的實例對象會在$instance屬性中記錄。回調(diào)函數(shù)的綁定在$bindings屬性中記錄。

有一種情況是綁定具體類名稱,實際上也是綁定回調(diào)函數(shù)的方式,只是回調(diào)函數(shù)是服務(wù)容器根據(jù)提供的參數(shù)自動生成的,下面章節(jié)我們會詳細(xì)講解。源碼中有如下代碼:

$app->singleton(
    IlluminateContractsDebugExceptionHandler::class,
    AppExceptionsHandler::class
);

$app->singleton(
    IlluminateContractsConsoleKernel::class,
    AppConsoleKernel::class
);

在服務(wù)綁定過程中,盡量使用接口名稱和服務(wù)進(jìn)行綁定,這樣可以使得一個具體的功能僅僅和接口實現(xiàn)了耦合,當(dāng)應(yīng)用需求變化時可以修改具體類,只要這個類還符合接口規(guī)范,程序依然可以健壯的運行。這種“面向接口”編程是一種新的,更有效的解決依賴的編程模式。Lumen框架的接口定義規(guī)范都放在/learnLumen/vendor/illuminate/contracts 文件夾下。

1.3、服務(wù)解析

服務(wù)綁定到容器之后,運行程序就可以隨時從容器中取出服務(wù),這個過程稱為“服務(wù)解析”。服務(wù)解析的步驟就是運行程序先獲取到容器對象,然后使用容器對象解析相應(yīng)的服務(wù)。服務(wù)解析有常用幾種方式:

使用保存服務(wù)容器成員屬性,調(diào)用make函數(shù)進(jìn)行解析

$this->app->make(AppServiceExampleService::class);

通過全局函數(shù)app()來獲取

app(AppServiceExampleService::class);

如果程序使用了Facades外觀,還可以通過靜態(tài)方法來解析

App::make(AppServiceExampleService::class);

服務(wù)容器類Container實現(xiàn)了ArrayAccess接口,可以使用數(shù)組的方式進(jìn)行服務(wù)解析

app[AppServiceExampleService::class];

ArrayAccess(數(shù)組式訪問)接口非常有用,提供了像訪問數(shù)組一樣訪問對象的能力的接口。

使用依賴注入的方式也可以實現(xiàn)服務(wù)的自動解析。即在類的構(gòu)造函數(shù)中,使用相應(yīng)的類提示符,容器會利用自身的反射機(jī)制自動解析依賴并實現(xiàn)注入。需要注意的是:在服務(wù)注冊以后使用依賴注入功能,則該服務(wù)名稱和服務(wù)是要遵循一定規(guī)范的。即服務(wù)名稱一般為服務(wù)生成的類名稱或者接口名稱,只有這樣當(dāng)服務(wù)根據(jù)依賴限制查找到服務(wù)后生成的實例對象才能滿足這個限制,否則就會報錯。

并不是Lumen框架中所有的類都能實現(xiàn)自動依賴注入的功能,只有“服務(wù)容器”創(chuàng)建的類實例才能實現(xiàn)依賴自動注入。

2.控制反轉(zhuǎn)(Ioc)和依賴注入(DI)

控制反轉(zhuǎn)是框架設(shè)計的一種原則,在很大程度上降低了代碼模塊之間的耦合度,有利于框架維護(hù)和拓展。實現(xiàn)控制反轉(zhuǎn)最常見的方法是“依賴注入”,還有一種方法叫“依賴查找”。控制反轉(zhuǎn)將框架中解決依賴的邏輯從實現(xiàn)代碼類庫的內(nèi)部提取到了外部來管理實現(xiàn)。

我們用簡單代碼模擬一下Lumen處理用戶請求的邏輯,框架中要使用到最簡單的Request請求模塊、Response請求模塊,我們使用單例模式簡單實現(xiàn)一下:

//Request模塊實現(xiàn)
class Request
{
    static private $instance = null;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    static function getInstance()
    {
        if (self::$instance == null) self::$instance = new self();
        return self::$instance;
    }

    public function get($key)
    {
        return $_GET[$key] ? $_GET[$key] : "";
    }

    public function post($key)
    {
        return $_POST[$key] ? $_POST[$key] : "";
    }
}

//Response模塊實現(xiàn)
class Response
{
    static private $instance = null;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    static function getInstance()
    {
        if (self::$instance == null) self::$instance = new self();
        return self::$instance;
    }

    public function json($data)
    {
        return json_encode($data);
    }
}

我們先來使用“依賴查找”的工廠模式來實現(xiàn)控制反轉(zhuǎn),我們需要一個工廠,簡單實現(xiàn)一下:

include_once "Request.php";
include_once "Response.php";
include_once "ExceptionHandler.php";

abstract class Factory
{
    static function Create($type, array $params = [])
    {
        //根據(jù)接收到的參數(shù)確定要生產(chǎn)的對象
        switch ($type) {
            case "request":
                return Request::getInstance();
                break;
            case "response":
                return Response::getInstance();
                break;
            case "exception":
                return new ExceptionHandler();
                break;
        }
    }
}

接下來就開始實現(xiàn)用戶邏輯,我們首先加入錯誤處理的簡單實現(xiàn):

//開啟報告代碼中的錯誤處理
class ExceptionHandler
{
    public function __construct()
    {
        error_reporting(-1);
        ini_set("display_errors", true);
    }
}

我們模擬一個請求用戶列表的邏輯:

include_once "Factory.php";

Factory::Create("exception");

//用戶邏輯
class UserLogic
{
    private $modules = [];

    public function __construct(array $modules)
    {
        foreach ($modules as $key => $module) {
            $this->modules[$key] = Factory::Create($module);
        }
    }

    public function getUserList()
    {
        if ($this->modules["request"]->get("path") == "userlist") {
            $userList = [
                ["name" => "張三", "age" => 18],
                ["name" => "李四", "age" => 22]
            ];

            return $this->modules["response"]->json($userList);
        }
    }
}

try {
    $userLogic = new UserLogic(["request" => "request", "response" => "response"]);
    echo $userLogic->getUserList();
} catch (Error $e) {
    var_dump($e);
    exit();
}

可以看到我們使用工廠模式管理依賴的時候,可以在處理業(yè)務(wù)邏輯外部根據(jù)處理請求需要依賴的模塊自行進(jìn)行注入。比如例子中就注入了request、response模塊。這種模式雖然解決了我們處理邏輯對外部模塊的依賴管理問題,但是并不是太完美,我們的程序只是將原來邏輯對一個個實例子對象的依賴轉(zhuǎn)換成了工廠對這些實例子對象的依賴,工廠和這些實例子對象之間的耦合還存在,隨著工廠越來越大,用戶邏輯實現(xiàn)越來越復(fù)雜,這種“依賴查找”實現(xiàn)控制反轉(zhuǎn)的模式對于用戶來講依然很痛苦。

接下來我們使用Ioc服務(wù)容器來實現(xiàn)依賴注入,下邊先實現(xiàn)一個簡單的服務(wù)容器:

class Container
{
    //用于裝提供實例的回調(diào)函數(shù),真正的容器還會裝實例等其他內(nèi)容
    protected $bindings = [];

    //容器共享實例數(shù)組(單例)
    protected $instances = [];

    public function bind($abstract, $concrete = null, $shared = false)
    {
        if (! $concrete instanceof Closure) {
            //如果提供的參數(shù)不是回調(diào)函數(shù),則產(chǎn)生默認(rèn)的回調(diào)函數(shù)
            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->bindings[$abstract] = compact("concrete", "shared");
    }

    public function getBuildings()
    {
        return $this->bindings;
    }

    //默認(rèn)生成實例的回調(diào)函數(shù)
    protected function getClosure($abstract, $concrete)
    {
        return function ($c) use ($abstract, $concrete)
        {
            $method = ($abstract == $concrete) ? "build" : "make";
            //調(diào)用的是容器的build或make方法生成實例
            return $c->$method($concrete);
        };
    }

    //生成實例對象,首先解決接口和要實例化類之間的依賴關(guān)系
    public function make($abstract)
    {
        $concrete = $this->getConcrete($abstract);
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($this->build($concrete));
        } else {
            $object = $this->make($concrete);
        }

        return $object;
    }

    protected function isBuildable($concrete, $abstract)
    {
        return $concrete === $abstract || $concrete instanceof Closure;
    }

    //獲取綁定的回調(diào)函數(shù)
    protected function getConcrete($abstract)
    {
        if (!isset($this->bindings[$abstract]))
        {
            return $abstract;
        }

        return $this->bindings[$abstract]["concrete"];
    }

    //實例化一個對象
    public function build($concrete)
    {
        if ($concrete instanceof Closure) {
            return $concrete($this);
        }
        $reflector = new ReflectionClass($concrete);
        if (! $reflector->isInstantiable()) {
            echo $message = "Target [$concrete] is not instantiable.";
        }
        $constructor = $reflector->getConstructor();
        if(is_null($constructor)) {
            return new $concrete;
        }
        $dependencies = $constructor->getParameters();
        $instances = $this->getDependencies($dependencies);

        return $reflector->newInstanceArgs($instances);
    }

    //通過反射機(jī)制實例化對象時的依賴
    protected function getDependencies($parameters)
    {
        $dependencies = [];
        foreach($parameters as $parameter)
        {
            $dependency = $parameter->getClass();
            if(is_null($dependency)) {
                $dependencies[] = NULL;
            } else {
                $dependencies[] = $this->resolveClass($parameter);
            }
        }

        return (array) $dependencies;
    }

    protected function resolveClass(ReflectionParameter $parameter)
    {
        return $this->make($parameter->getClass()->name);
    }

    //注冊一個實例并綁定到容器中
    public function singleton($abstract, $concrete = null){
        $this->bind($abstract, $concrete, true);
    }
}

該服務(wù)容器可以稱為Lumen服務(wù)容器的簡化版,但是它實現(xiàn)的功能和Lumen服務(wù)容器是一樣的,雖然只有一百多行的代碼,但是理解起來有難度,這里就詳細(xì)講解清楚簡化版容器的代碼和原理,接下來章節(jié)對Lumen服務(wù)容器源碼分析時就僅僅只對方法做簡單介紹。

根據(jù)對服務(wù)容器介紹章節(jié)所講:容器中有兩個關(guān)鍵屬性$bindings和$instance,其中$bindings中存在加入到容器中的回調(diào)函數(shù),而$instance存放的是容器中綁定的實例對象。我們還知道$singleton方法用來綁定單例對象,其底層只是調(diào)用了bind方法而已,只不過$shared屬性為true,意為容器中全局共享:

//注冊一個實例并綁定到容器中
public function singleton($abstract, $concrete = null){
    $this->bind($abstract, $concrete, true);
}

bind方法的實現(xiàn)也很簡單,只是將用戶指定的服務(wù)解析好之后存放入相應(yīng)的屬性當(dāng)中:

public function bind($abstract, $concrete = null, $shared = false)
    {
        if (! $concrete instanceof Closure) {
            //如果提供的參數(shù)不是回調(diào)函數(shù),則產(chǎn)生默認(rèn)的回調(diào)函數(shù)
            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->bindings[$abstract] = compact("concrete", "shared");
    }

Closure是php中的匿名函數(shù)類類型。$abstract和$concrete可以抽象理解為KV鍵值對,K就是$abstract,是服務(wù)名;V是$concrete,是服務(wù)的具體實現(xiàn)。我們理解容器,首先要將思維從平常的業(yè)務(wù)邏輯代碼中轉(zhuǎn)換回來。業(yè)務(wù)邏輯中操作的一般是用戶數(shù)據(jù),而容器中,我們操作的是對象、類、接口之類的,在框架中可稱為“服務(wù)”。如果用戶要綁定的具體實現(xiàn)$concrete不是匿名函數(shù),則調(diào)用getClosure方法生成一個匿名函數(shù):

//獲取綁定的回調(diào)函數(shù)
    //默認(rèn)生成實例的回調(diào)函數(shù)
    protected function getClosure($abstract, $concrete)
    {
        return function ($c) use ($abstract, $concrete)
        {
            $method = ($abstract == $concrete) ? "build" : "make";
            //調(diào)用的是容器的build或make方法生成實例
            return $c->$method($concrete);
        };
    }

getClosure是根據(jù)用戶傳入的參數(shù)來決定調(diào)用系統(tǒng)的build和make方法。其中build方法就是構(gòu)建匿名函數(shù)和類實例的關(guān)鍵實現(xiàn),使用了php中的反射機(jī)制,解析出類實例:

//實例化一個對象
    public function build($concrete)
    {
        if ($concrete instanceof Closure) {
            return $concrete($this);
        }
        $reflector = new ReflectionClass($concrete);
        if (! $reflector->isInstantiable()) {
            echo $message = "Target [$concrete] is not instantiable.";
        }
        $constructor = $reflector->getConstructor();
        if(is_null($constructor)) {
            return new $concrete;
        }
        $dependencies = $constructor->getParameters();
        $instances = $this->getDependencies($dependencies);

        return $reflector->newInstanceArgs($instances);
    }

build首先判斷參數(shù)$concrete是一個匿名函數(shù),就返回調(diào)用匿名函數(shù)的一個閉包。否則$concrete是一個類,利用反射機(jī)制解析類的信息,首先判斷類是否能夠被實例化(例如單例就不能被實例化,容器中的單例是通過屬性$shared來區(qū)分的);確保了類能夠被實例化以后,使用getConstructor()判斷類是否定義了構(gòu)造函數(shù),如果沒有定義構(gòu)造函數(shù),直接實例化得到一個類的實例。否則就再次調(diào)用getParameters獲取構(gòu)造函數(shù)中都傳入了哪些參數(shù)(也就是判斷$concrete類都有哪些依賴),getDependencies方法就是來生成$concrete依賴的函數(shù):

    //通過反射機(jī)制實例化對象時的依賴
    protected function getDependencies($parameters)
    {
        $dependencies = [];
        foreach($parameters as $parameter)
        {
            $dependency = $parameter->getClass();
            if(is_null($dependency)) {
                $dependencies[] = NULL;
            } else {
                $dependencies[] = $this->resolveClass($parameter);
            }
        }

        return (array) $dependencies;
    }

得到了類依賴的實例以后,就調(diào)用newInstanceArgs($instances)來生成類的實例。

服務(wù)解析函數(shù)make主要由build函數(shù)實現(xiàn):

    //生成實例對象,首先解決接口和要實例化類之間的依賴關(guān)系
    public function make($abstract)
    {
        $concrete = $this->getConcrete($abstract);
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($this->build($concrete));
        } else {
            $object = $this->make($concrete);
        }

        return $object;
    }

有了服務(wù)容器以后,我們就可以使用服務(wù)容器來存儲處理請求中需要的服務(wù),并實現(xiàn)服務(wù)中的依賴自動注入。不過首先我們需要將Request、Response單例做修改,因為服務(wù)容器對單例的管理,是通過$shared屬性進(jìn)行設(shè)置的。所以Request、Response要能夠被實例化,才能保存到容器的$bindings數(shù)組中:

class Request
{

    public function __construct()
    {
    }

    public function get($key)
    {
        return $_GET[$key] ? $_GET[$key] : "";
    }

    public function post($key)
    {
        return $_POST[$key] ? $_POST[$key] : "";
    }
}

class Response
{
    public function __construct()
    {
    }

    public function json($data)
    {
        return json_encode($data);
    }
}

我們再來看使用容器后處理用戶請求的源代碼:

include_once "Container.php";
include_once "Request.php";
include_once "Response.php";
include_once "ExceptionHandler.php";

$app = new Container();
//綁定錯誤處理
$app->bind("exception", "ExceptionHandler");
//將請求、響應(yīng)單例組件添加到容器中
$app->singleton("request", "Request");
$app->singleton("response", "Response");
//解析錯誤處理
$app->make("exception");

//用戶邏輯
class UserLogic
{
    public $app = null;

    public function __construct(Container $app)
    {
        $this->app = $app;
    }

    public function getUserList()
    {
        if ($this->app->make("request")->get("path") == "userlist") {
            $userList = [
                ["name" => "張三", "age" => 18],
                ["name" => "李四", "age" => 22]
            ];

            return $this->app->make("response")->json($userList);
        }
    }
}

try {
    $userLogic = new UserLogic($app);
    echo $userLogic->getUserList();
} catch (Error $e) {
    var_dump($e);
    exit();
}

我們還是按照之前的步驟,使用容器將錯誤處理類綁定到容器中,然后解析出來使用。使用singleton方法將Request和Response類綁定到容器中,類型是單例。這樣我們管理服務(wù)模塊、實現(xiàn)依賴注入這些問題全都交給容器來做就好了。我們想要什么樣的服務(wù),就向容器中添加,在需要使用的時候,就利用容器解析使用就可以了。lumen框架中的服務(wù)容器是全局的,不需要像例子中一樣,手動注入到邏輯代碼中使用。

3.源碼解析

對于lumen框架來講,服務(wù)容器相當(dāng)于發(fā)動機(jī),綁定與解析框架啟動和運行生命周期中所有的服務(wù)。它的大致架構(gòu)如下所示:

3.1、服務(wù)容器綁定的方法

bind綁定

bindif綁定

singleton綁定

instance綁定

context綁定

數(shù)組綁定

標(biāo)簽綁定

extend拓展

Rebounds與Rebinding

源碼中bind實現(xiàn)代碼如下:

public function bind($abstract, $concrete = null, $shared = false)
    {
        $this->dropStaleInstances($abstract);

        if (is_null($concrete)) {
            $concrete = $abstract;
        }

        if (! $concrete instanceof Closure) {
            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->bindings[$abstract] = compact("concrete", "shared");

        if ($this->resolved($abstract)) {
            $this->rebound($abstract);
        }
    }

從源碼中我們可知:使用bind方法綁定服務(wù),每次都會重新進(jìn)行綁定(刪除原來的綁定,再重新綁定)。我們類比服務(wù)容器中服務(wù)的綁定為KV健值對。key為接口名稱,而value為具體的服務(wù)實現(xiàn),之所以推薦使用接口名稱作為key,是因為只要開發(fā)者遵循相關(guān)的接口約束規(guī)范,就可以對服務(wù)進(jìn)行拓展和改進(jìn),這也是面向接口編程比較新穎之處。另外我們可以看到bind方法核心實現(xiàn)方法是調(diào)用rebound方法。

bindif方法核心是調(diào)用bind方法,只不過對容器是否綁定服務(wù)做了一個判斷:

public function bindIf($abstract, $concrete = null, $shared = false)
    {
        if (! $this->bound($abstract)) {
            $this->bind($abstract, $concrete, $shared);
        }
    }

singleton是bind方法的一種特例,shared=true表示為單例綁定:

 public function singleton($abstract, $concrete = null)
    {
        $this->bind($abstract, $concrete, true);
    }

instance是綁定對象實例到容器中(不用使用make進(jìn)行解析了):

public function instance($abstract, $instance)
    {
        $this->removeAbstractAlias($abstract);

        $isBound = $this->bound($abstract);

        unset($this->aliases[$abstract]);

        $this->instances[$abstract] = $instance;

        if ($isBound) {
            $this->rebound($abstract);
        }

        return $instance;
    }

數(shù)組綁定是Container類繼承了ArrayAccess接口,在offsetSet中調(diào)用了bind方法進(jìn)行注冊:

public function offsetSet($key, $value)
    {
        $this->bind($key, $value instanceof Closure ? $value : function () use ($value) {
            return $value;
        });
    }

extend方法實現(xiàn)了當(dāng)原來的類注冊或者實例化出來后,對其進(jìn)行拓展:

public function extend($abstract, Closure $closure)
    {
        $abstract = $this->getAlias($abstract);

        if (isset($this->instances[$abstract])) {
            $this->instances[$abstract] = $closure($this->instances[$abstract], $this);

            $this->rebound($abstract);
        } else {
            $this->extenders[$abstract][] = $closure;

            if ($this->resolved($abstract)) {
                $this->rebound($abstract);
            }
        }
    }

Context綁定是針對于兩個類使用同一個接口,但是我們在類中注入了不同的實現(xiàn),這時候我們就需要使用when方法了:

 public function when($concrete)
    {
        $aliases = [];

        foreach (Arr::wrap($concrete) as $c) {
            $aliases[] = $this->getAlias($c);
        }

        return new ContextualBindingBuilder($this, $aliases);
    }

繼續(xù)看ContextualBindingBuilder類的源碼我們知道,上下文綁定的基本思路就是$this->app->when()->needs()->give();
比如有幾個控制器分別依賴IlluminateContractsFilesystemFilesystem的不同實現(xiàn):

$this->app->when(StorageController::class)
          ->needs(Filesystem::class)
          ->give(function () {
            Storage::class
          });//提供類名

$this->app->when(PhotoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
             return new Storage();
          });//提供實現(xiàn)方式

$this->app->when(VideoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
            return new Storage($app->make(Disk::class));
          });//需要依賴注入

有一些場景,我們希望當(dāng)接口改變以后對已實例化的對象重新做一些改變,這就是rebinding 函數(shù)的用途:

  public function rebinding($abstract, Closure $callback)
    {
        $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback;

        if ($this->bound($abstract)) {
            return $this->make($abstract);
        }
    }
3.2、服務(wù)別名

在服務(wù)容器解析之前,Lumen框架會將常用的服務(wù)起一些別名,方便系統(tǒng)Facade方法調(diào)用和解析。

public function withAliases($userAliases = [])
    {
        $defaults = [
            "IlluminateSupportFacadesAuth" => "Auth",
            "IlluminateSupportFacadesCache" => "Cache",
            "IlluminateSupportFacadesDB" => "DB",
            "IlluminateSupportFacadesEvent" => "Event",
            "IlluminateSupportFacadesGate" => "Gate",
            "IlluminateSupportFacadesLog" => "Log",
            "IlluminateSupportFacadesQueue" => "Queue",
            "IlluminateSupportFacadesRoute" => "Route",
            "IlluminateSupportFacadesSchema" => "Schema",
            "IlluminateSupportFacadesStorage" => "Storage",
            "IlluminateSupportFacadesURL" => "URL",
            "IlluminateSupportFacadesValidator" => "Validator",
        ];

        if (! static::$aliasesRegistered) {
            static::$aliasesRegistered = true;

            $merged = array_merge($defaults, $userAliases);

            foreach ($merged as $original => $alias) {
                class_alias($original, $alias);
            }
        }
    }
    ...
    protected function registerContainerAliases()
    {
        $this->aliases = [
            "IlluminateContractsFoundationApplication" => "app",
            "IlluminateContractsAuthFactory" => "auth",
            "IlluminateContractsAuthGuard" => "auth.driver",
            "IlluminateContractsCacheFactory" => "cache",
            "IlluminateContractsCacheRepository" => "cache.store",
            "IlluminateContractsConfigRepository" => "config",
            "IlluminateContainerContainer" => "app",
            "IlluminateContractsContainerContainer" => "app",
            "IlluminateDatabaseConnectionResolverInterface" => "db",
            "IlluminateDatabaseDatabaseManager" => "db",
            "IlluminateContractsEncryptionEncrypter" => "encrypter",
            "IlluminateContractsEventsDispatcher" => "events",
            "IlluminateContractsHashingHasher" => "hash",
            "log" => "PsrLogLoggerInterface",
            "IlluminateContractsQueueFactory" => "queue",
            "IlluminateContractsQueueQueue" => "queue.connection",
            "request" => "IlluminateHttpRequest",
            "LaravelLumenRoutingRouter" => "router",
            "IlluminateContractsTranslationTranslator" => "translator",
            "LaravelLumenRoutingUrlGenerator" => "url",
            "IlluminateContractsValidationFactory" => "validator",
            "IlluminateContractsViewFactory" => "view",
        ];
    }
    ......

lumen服務(wù)容器中通過alias方法添加服務(wù)別名:

    public function alias($abstract, $alias)
    {
        $this->aliases[$alias] = $abstract;

        $this->abstractAliases[$abstract][] = $alias;
    }

通過getAlias獲得服務(wù)的別名:

public function getAlias($abstract)
    {
        if (! isset($this->aliases[$abstract])) {
            return $abstract;
        }

        if ($this->aliases[$abstract] === $abstract) {
            throw new LogicException("[{$abstract}] is aliased to itself.");
        }

        return $this->getAlias($this->aliases[$abstract]);

通過getAlias我們知道,服務(wù)別名是支持遞歸設(shè)置的。

3.3、其他函數(shù)簡述

服務(wù)容器解析一個對象時會觸發(fā)resolving和afterResolving函數(shù)。分別在之前之后觸發(fā):

public function resolving($abstract, Closure $callback = null)
    {
        if (is_string($abstract)) {
            $abstract = $this->getAlias($abstract);
        }

        if (is_null($callback) && $abstract instanceof Closure) {
            $this->globalResolvingCallbacks[] = $abstract;
        } else {
            $this->resolvingCallbacks[$abstract][] = $callback;
        }
    }

    public function afterResolving($abstract, Closure $callback = null)
    {
        if (is_string($abstract)) {
            $abstract = $this->getAlias($abstract);
        }

        if ($abstract instanceof Closure && is_null($callback)) {
            $this->globalAfterResolvingCallbacks[] = $abstract;
        } else {
            $this->afterResolvingCallbacks[$abstract][] = $callback;
        }
    }

服務(wù)容器中有一些裝飾函數(shù),wrap裝飾call,factory裝飾make:

public function call($callback, array $parameters = [], $defaultMethod = null)
    {
        return BoundMethod::call($this, $callback, $parameters, $defaultMethod);
    }

......

public function wrap(Closure $callback, array $parameters = [])
    {
        return function () use ($callback, $parameters) {
            return $this->call($callback, $parameters);
        };
    }

服務(wù)容器的解析方法和函數(shù)之前已經(jīng)說過,有幾種常用的方法,這里就不再一一贅述了。

可以服務(wù)容器中flush()方法用于清空容器中所有的服務(wù):

  public function flush()
    {
        $this->aliases = [];
        $this->resolved = [];
        $this->bindings = [];
        $this->instances = [];
        $this->abstractAliases = [];
    }

Lumen中的服務(wù)容器源碼實現(xiàn)非常復(fù)雜,但是對其工作原理了解清楚之后,看起來也就有些頭緒了,每個函數(shù)所做的工作也可以結(jié)合注釋和源碼進(jìn)行理解了。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/31265.html

相關(guān)文章

  • Lumen 初體驗(二)

    摘要:的現(xiàn)狀目前是版本,是基于開發(fā)。入口文件啟動文件和配置文件框架的入口文件是。在路由中指定控制器類必須寫全命名空間,不然會提示找不到類。目前支持四種數(shù)據(jù)庫系統(tǒng)以及。使用時發(fā)生錯誤,因為在文件中,的默認(rèn)驅(qū)動是。 最近使用 Lumen 做了 2 個業(yè)余項目,特此記錄和分享一下。 Lumen 的介紹 在使用一項新的技術(shù)時,了解其應(yīng)用場景是首要的事情。 Lumen 的口號:為速度而生的 La...

    Cheriselalala 評論0 收藏0
  • Lumen用戶認(rèn)證JWT,源碼解讀

    摘要:如何做用戶認(rèn)證根據(jù)文檔描述,提供用戶認(rèn)證的接口,他的核心是看守器和提供器,看守器定義怎么認(rèn)證用戶,提供器定義怎么檢索用戶。 最近的一個PHP項目,上一個項目是采用ThinkPHP來弄的,因為很早就聽說過Laravel的大名,所以進(jìn)了Laravel的官網(wǎng),意外發(fā)現(xiàn)了Lumen,正好我項目是提供API的,所以選擇了Lumen,因為是Laravel的精簡版,看了幾天的Laravel文檔,也總...

    AZmake 評論0 收藏0
  • Lumen配置文件按需加載出現(xiàn)的坑

    摘要:問題分析通過閱讀源碼發(fā)現(xiàn),中的服務(wù)都是按需綁定并加載。在服務(wù)按需綁定并加載的時候,使用了類似組件的形式通過載入配置項并綁定服務(wù)。因為在這個時候的相關(guān)配置文件還沒有被載入。 問題描述 公司一個高并發(fā)API需要從Laravel移植到Lumen,由于數(shù)據(jù)庫配置信息是通過遠(yuǎn)程或者緩存讀取后動態(tài)配置,所以在中間件時使用到了 Config::set 然而實際運行時發(fā)現(xiàn)數(shù)據(jù)庫配置并沒有更新。 由于是...

    lentoo 評論0 收藏0
  • 學(xué)習(xí) Lumen 用戶認(rèn)證 (一)

    摘要:在開發(fā)中,用戶認(rèn)證是核心,是數(shù)據(jù)是否有保障的前提,目前主要有兩種常用方式進(jìn)行用戶認(rèn)證和。附是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于的開放標(biāo)準(zhǔn)。 好久沒寫 PHP 代碼了,尤其是 Lumen,我是 Lumen 的忠實用戶,自從面世開始,我就將 Lumen 作為我 API 的主要框架使用。 但說到 API,不得不說的一個概念:「前后端分離」,現(xiàn)在越來越多的團(tuán)隊都采用前后端分離,徹底解...

    wangzy2019 評論0 收藏0
  • lumen5.5學(xué)習(xí)(二)

    摘要:繼續(xù)學(xué)習(xí)分割線看看是怎么輸出這個數(shù)據(jù)目錄下的加載了下的的自動加載加載的配置初始化應(yīng)用初始化的內(nèi)容指定項目基礎(chǔ)目錄注冊服務(wù)容器注冊異常處理實例 繼續(xù)學(xué)習(xí)lumen5.5 -----------------------分割線----------------------- 看看是怎么輸出Lumen (5.5.2) (Laravel Components 5.5.*)這個數(shù)據(jù) public目錄...

    shengguo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<