Laravel简单版IOC服务容器学习笔记

内容来自 - 《Laravel框架关键技术解析》

控制反转:将组件(类)间的依赖关系从程序内部提到外部容器(IOC服务容器)来管理;
依赖注入:将组件(类)的依赖通过外部以参数或其他形式来注入;
控制反转和依赖注入本质上指的都是一个意思;

<?php

//简化版服务容器

class Container
{
    protected $bindings = [];

    //绑定接口和生成相应实例的回调函数
    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)
    {
        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 "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) {
            $dependency = $parameter->getClass();
            if (is_null($dependency)) {
                $dependencies[] = null;
            } else {
                $dependencies[] = $this->resolveClass($parameter);
            }
        }

        return $dependencies;
    }

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


}

使用例子展示

<?php

//使用控制反转,依赖注入解决类之间的依赖

//旅游场景说明
interface Visit
{
    public function go();
}

class Leg implements Visit
{
    public function go()
    {
        echo 'walk to Beijing' . PHP_EOL;
    }
}

class Car implements Visit
{
    public function go()
    {
        echo 'drive car to Beijing' . PHP_EOL;
    }
}

class Train implements Visit
{
    public function go()
    {
        echo 'go to Beijing by train' . PHP_EOL;
    }
}

//旅游者
class Traveller
{
    protected $trafficTool;

    public function __construct(Visit $trafficTool)
    {

        // $this->trafficTool = new Leg();
        //从内部实例化依赖转变为通过外部注入依赖的方式
        $this->trafficTool = $trafficTool;
    }

    public function visit()
    {
        $this->trafficTool->go();
    }

}


//客户端调用 依赖注入方式
// $visit = new Car();
// $traveller = new Traveller($visit);
// $traveller->visit();

//使用服务容器来实现依赖注入
require_once './Container.php';

$container = new Container();

$container->bind('Visit', 'Leg');
$container->bind('traveller', 'Traveller');

$traveller = $container->make('traveller');
$traveller->visit();