Laravel服务容器

laravel框架底层解析

本文参考陈昊《Laravel框架关键技术解析》,搭建一个属于自己的简化版服务容器。
其中涉及到反射、自动加载,还是需要去了解一下。

laravel服务容器

  1. 建立项目空文件夹(如 mylaravel)

  2. 添加composer.json,执行composer install

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

目的是为了学习、利用composer的自动加载。

  1. 文件路径如下所示

  • mylaravel

    • app

      • Traveller

        • Traveller.php

      • Visit

        • 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();
    原文作者:luzhuqun
    原文地址: https://segmentfault.com/a/1190000008473139
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞