美文网首页
核心:laravel容器 依赖反转

核心:laravel容器 依赖反转

作者: lifefruity | 来源:发表于2020-02-24 14:47 被阅读0次
  1. 简单版的
<?php 

interface SuperModuleInterface
{
    public function activate(array $target);
}

class XPower implements SuperModuleInterface
{
    public function activate(array $target)
    {
        // something
    }
}

class UltraBomb implements SuperModuleInterface
{
    public function activate(array $target)
    {
        // something
    }
}

class Superman
{
    protected $module;
 
    public function __construct(SuperModuleInterface $module)
    {
        $this->module = $module;
    }
}

class Container
{
    protected $binds;
 
    protected $instances;
 
    public function bind($abstract, $concrete)
    {
        if ($concrete instanceof Closure) {
            $this->binds[$abstract] = $concrete;
        }
//        else {
//            $this->instances[$abstract] = $concrete;
//        }
    }
 
    public function make($abstract, $parameters = [])
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
 
        array_unshift($parameters, $this);
        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}



$container = new Container;
 
// 向该 超级工厂 添加 超人 的生产脚本
$container->bind('superman', function($container, $moduleName) {//call_user_func_array里的参数array_unshift里的参数
    return new Superman($container->make($moduleName));
});
 
// 向该 超级工厂 添加 超能力芯片 的生产脚本
$container->bind('xpower', function($container) {
    return new XPower;
});
 
// 同上
$container->bind('ultrabomb', function($container) {
    return new UltraBomb;
});

// 开始启动生产
$superman = $container->make('superman', ['ultrabomb']);
echo "<pre>";var_dump($superman);
/*
输出
object(Superman)#5 (1) {
  ["module":protected]=>
  object(UltraBomb)#6 (0) {
  }
}
*/

  1. 通过反射 容器 实现自动实例化类
<?php

class Container{
    protected $bindings = [];

    public function bind($abstract, $concrete = null, $shared = false){
        //echo 'start to bind: '.($abstract)."\n";
        if(!$concrete instanceof Closure){
            //echo 'get closure '. $abstract. ':' . $concrete."\n";
            $concrete = $this->getClosure($abstract, $concrete);
//            if($abstract == 'traveller'){
//                var_dump($concrete);
//            }
        }
        $this->bindings[$abstract] = compact('concrete', 'shared');//都是匿名函数
    }

    protected function getClosure($abstract, $concrete){
        $x = function ($c) use($abstract, $concrete){
            $method = ($abstract == $concrete) ? 'build' : 'make';//相同的话直接实例化
            return $c->$method($concrete);
        };
        //var_dump($x);exit;
        return $x;
    }

    public function make($abstract){//todo traveller Traveller Visit可以理解。为什么还有个Leg?因为Visit作为abstract后有个Leg
        $concrete = $this->getConcrete($abstract);//注释1 那里注释了也可以运行,因为这里自动生成了$concrete $abstract
        if($this->isBuildable($concrete, $abstract)){//todo 精华,用traveller代入make方法的$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){
            $dependency = $parameter->getClass();
            if(is_null($dependency)){
                $dependencies[] = null;
            }else{
                $dependencies[] = $this->resolveClass($parameter);
            }
        }
        return (array)$dependencies;
    }

    protected function resolveClass(ReflectionParameter $parameter){//解决构造函数里的那个Visit
        // $parameter->getClass()->name就是Visit
        return $this->make($parameter->getClass()->name);
    }
}

interface Visit{
    public function go();
}

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

class Leg implements Visit{
    public function go(){
        echo 'go to by Leg';
    }
}

class Traveller{
    protected $trafficTool;

    public function __construct(Visit $trafficTool)
    {
        $this->trafficTool = $trafficTool;
    }

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

class jackC{
    public function __construct($what){
        echo 'construct ' . $what."\n";
    }

    public function visitTibet(){
        echo 'this is made by jack.';
    }
}

$app = new Container();
$app->bind('Visit', 'Leg');
$app->bind('traveller', 'Traveller');//去掉这行也可以运行???因为 class Abc{}  $obj = new abc(); 也可以。加的原因是在注释1
//$app->bind('traveller', function(){//方法一。这里的bind可以直接bind一个匿名函数。
//    return new jackC();
//});
//$app->bind('traveller', 'jackC');//方法二。todo,如何传参
$tra = $app->make('traveller');
$tra->visitTibet();

2.1 解释说明2
打印

string(9) "traveller"
string(13) "--start build"
string(37) "---start, traveller-Traveller to make"
string(28) "Traveller 也是buildAble的"
string(9) "Traveller"
string(13) "--start build"
string(34) "--build not Closure ==== Traveller"
string(5) "Visit"
string(13) "--start build"
string(27) "---start, Visit-Leg to make"
string(3) "Leg"
string(13) "--start build"
string(28) "--build not Closure ==== Leg"
go to by Leg
<?php

class Container{
    protected $bindings = [];

    public function bind($abstract, $concrete = null, $shared = false){
        //echo 'start to bind: '.($abstract)."\n";
        if(!$concrete instanceof Closure){
            //echo 'get closure '. $abstract. ':' . $concrete."\n";
            $concrete = $this->getClosure($abstract, $concrete);
//            if($abstract == 'traveller'){
//                var_dump($concrete);
//            }
        }
        $this->bindings[$abstract] = compact('concrete', 'shared');//都是匿名函数
    }

    protected function getClosure($abstract, $concrete){
        $x = function ($c) use($abstract, $concrete){
            $method = ($abstract == $concrete) ? 'build' : 'make';//相同的话直接实例化

            var_dump('---start, ' . $abstract  . '-' . $concrete. ' to ' . $method);
            return $c->$method($concrete);
        };
        //var_dump($x);exit;
        return $x;
    }


    /*
     * 先是make的时候traveller,进去了
     * getClosure()里traveller和Travellers不一致,所以make
     * */

    public function make($abstract){//todo traveller Traveller Visit可以理解。为什么还有个Leg?因为Visit作为abstract后有个Leg
        $concrete = $this->getConcrete($abstract);//注释1 那里注释了也可以运行,因为这里自动生成了$concrete $abstract
        if($this->isBuildable($concrete, $abstract)){//todo 精华,用traveller代入make方法的$abstract里,一步步想 !!!!!!!!!!!!
            var_dump($abstract);
            /*
             * //这里var_dump($abstract)打印的顺序是
             * string(9) "traveller"
                string(9) "Traveller"
                string(5) "Visit"
                string(3) "Leg"
            ,但是放到build后面,就反了,奇怪!!!!!!!!!!!!!!
             * */
            $object = $this->build($concrete);
        }
        return $object;
    }

    protected function isBuildable($concrete, $abstract){
        if($concrete == 'Traveller' && $abstract == 'Traveller'){
            var_dump('Traveller 也是buildAble的');
        }
        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){
        var_dump('--start build');
        if($concrete instanceof Closure){
            return $concrete($this);
        }else{
            var_dump('--build not Closure ==== ' . $concrete);
        }
        $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();//构造函数里的参数

        //$dependencies 是构造函数里的参数,这里是$trafficToollll
        $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{
                //通过Visit  $trafficToollll ,解析出来是绑定过的Leg
                $dependencies[] = $this->resolveClass($parameter);
            }
        }
        return (array)$dependencies;
    }

    protected function resolveClass(ReflectionParameter $parameter){//解决构造函数里的那个Visit
        // $parameter->getClass()->name就是Visit
        return $this->make($parameter->getClass()->name);
    }
}

interface Visit{
    public function go();
}

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

class Leg implements Visit{
    public function go(){
        echo 'go to by Leg';
    }
}

class Traveller{
    protected $trafficTool;

    public function __construct(Visit $trafficToollll)
    {
        $this->trafficTool = $trafficToollll;
    }

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

class jackC{
    public function __construct($what){
        echo 'construct ' . $what."\n";
    }

    public function visitTibet(){
        echo 'this is made by jack.';
    }
}

echo "<pre>";
$app = new Container();
$app->bind('Visit', 'Leg');
$app->bind('traveller', 'Traveller');//去掉这行也可以运行???因为 class Abc{}  $obj = new abc(); 也可以。加的原因是在注释1

//$app->bind('traveller', function(){//方法一。这里的bind可以直接bind一个匿名函数。
//    return new jackC();
//});
//$app->bind('traveller', 'jackC');//方法二。todo,如何传参

$tra = $app->make('traveller');

$tra->visitTibet();

相关文章

网友评论

      本文标题:核心:laravel容器 依赖反转

      本文链接:https://www.haomeiwen.com/subject/pvrvqhtx.html