Laravel服務容器

laravel框架底層解析

本文參考陳昊《Laravel框架關鍵技術解析》,搭建一個屬於本身的簡化版服務容器。
其中涉及到反射、自動加載,仍是須要去了解一下。php

laravel服務容器

  1. 創建項目空文件夾(如 mylaravel)laravel

  2. 添加composer.json,執行composer installjson

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "autoload": {
        "classmap": [
        ],
        "psr-4": {
            "App\\": "app/"
        }
    }
}

目的是爲了學習、利用composer的自動加載。app

  1. 文件路徑以下所示composer

  • mylaravel框架

    • app函數

      • Traveller學習

        • Traveller.phpui

      • Visitthis

        • Leg.php

        • Visit.php

      • Container.php

      • Index.php

    • vendor

    • composer.json

  1. 簡化版Container.php

<?php
namespace App;

Class Container
{
    protected $bindings = [];

    /**
     * 綁定接口和生成相應實例的回調函數
     * @param $abstract 服務名稱
     * @param null $concreate 回調函數或名稱
     * @param bool $shared 是否爲單例
     *
     */
    public function bind($abstract, $concrete = null, $shared = false)
    {
        if ( ! $concrete instanceof \Closure) {
            // 若是提供的參數不是回調函數,則產生默認的回調函數
            $concrete = $this->getClosure($abstract, $concrete);
        }
    
        $this->bindings[$abstract] = compact('concrete', 'shared');
    
    }
    //默認的回調函數
    protected function getClosure($abstract, $concrete)
    {
        //生成實例的回調函數, $c通常爲ioc容器對象
        return function($c) use ($abstract, $concrete)
        {
            $method = ($abstract == $concrete) ? 'build' : 'make';
            return $c->$method($concrete);
        };
    }
    //生成實例對象,首先解決接口和要實例化類之間的依賴
    public function make($abstract)
    {
        $concrete = $this->getConcrete($abstract);
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }
        return $object;
    }
    protected function isBuildable($concrete, $abstract)
    {
        return $concrete === $abstract || $concrete instanceof \Closure;
    }
    //獲取綁定的回調函數
    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);
    }
    protected function getDependencies($parameters)
    {
        $dependencies = [];
        foreach ($parameters as $parameter)
        {
            $denpendency = $parameter->getClass();
            if (is_null($denpendency)) {
                $dependencies[] = NULL;
            } else {
                $dependencies[] = $this->resolveClass($parameter);
            }
        }
        return (array) $dependencies;
    }
    protected function resolveClass(\ReflectionParameter $parameter)
    {
        return $this->make($parameter->getClass()->name);
    }
}

Visit.php接口

<?php
namespace App\Visit;

interface Visit
{
    public function go();
}

Leg.php接口的一種實現

<?php
namespace App\Visit;

Class Leg implements Visit
{
    public function go()
    {
        echo "walk to tibet!";
    }
}

Traveller.php至關於Controller下的方法

<?php
namespace App\Traveller;

use App\Visit\Visit;

Class Traveller
{
    protected $trafficTool;
    //Visit是抽象類,index中將leg注入到了容器,取代了Visit
    public function __construct(Visit $visit)
    {
        $this->trafficTool = $visit;
    }
    public function visitTibet()
    {
        $this->trafficTool->go();
    }
}

Index.php

<?php 
namespace App;

//調用composer的自動加載
require '../vendor/autoload.php';

Class Index
{
    public function index()
    {
            //實例化ioc容器
            $app = new Container();
            //容器填充
            $app->bind('App\Visit\Visit', '\App\Visit\Leg');
            $app->bind('Traveller', '\App\Traveller\Traveller');
            //經過容器實現依賴注入,完成類的實例化
            $tra = $app->make("\App\Traveller\Traveller");
            $tra->visitTibet();
    }
}

$b = new Index;
$b->index();
相關文章
相關標籤/搜索