204 IOC 仿照laravel实现一个最简容器 2

本文介绍了一个基于PHP的简易依赖注入容器实现,通过闭包方式完成服务绑定与解析,展示了核心功能及执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仿照laravel实现一个最简容器 2

一、闭包实现bind

由此我们实现了容器的核心功能

<?php

class Ioc{
    protected $bindings = [];

    function bind($abstract,$concrete = null,$shared = 0){
        echo "step bind   abstract : [$abstract] <br/>";
        if (!$concrete instanceof Closure){
            $concrete = $this->getClosure($abstract,$concrete);
        }

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

    }

    function getClosure($abstract,$concrete){

           return function ($c) use ($abstract,$concrete){

               echo "step getClosure   abstract : [$abstract] , concrete : [$concrete] <br/>";

               $method = ($abstract == $concrete) ? 'build' : 'make';
               return $c->$method($concrete);
           };
    }

    function make($abstract){
        $concrete = $this->getConcrete($abstract);

        echo "step make  abstract : [$abstract] , abstract : [$abstract] <br/>";
        if ($this->isBuildable($concrete,$abstract)){
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }
        return $object;

    }

    public function getConcrete($abstract){
        echo "step getConcrete  abstract : [$abstract] <br/>";

        if (isset($this->bindings[$abstract])){
            // var_dump($this->bindings[$abstract]['concrete']);
            // 这里会返回bind的时候绑定的闭包,但是闭包未被调用
            return $this->bindings[$abstract]['concrete'];
        }

        return $abstract;
    }

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

    function build($concrete){
        if ($concrete instanceof Closure){
            echo "step build  <br/>";
        } else {
            echo "step build  concrete : [$concrete] <br/>";
        }

        if ($concrete instanceof Closure){
            //到这里getClosure 才第一次被执行
            return $concrete($this);
        }

        //下面的情况应该是对应 $abstract == $concrete
        $reflector = new ReflectionClass($concrete);
        if (! $reflector->isInstantiable()){
            echo $message = "target [$concrete] is not isInstantiable";
        }

        $constructor = $reflector->getConstructor();
        if (is_null($constructor)){
            return new $concrete;
        }
        $dependencies = $constructor->getParameters();
        $instances = $this->getDependencies($dependencies);
        return $reflector->newInstanceArgs($instances);
    }

    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;
    }

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

interface Tool{
    function go();
}

class Train implements Tool{
    function go(){
        echo "drive to tibet";
    }
}

$app = new ioc();
$app->bind('tool','Train');
$tool = $app->make('tool');

二、分析下执行流程

上面的代码执行之后会得到如下结果

step bind abstract : [tool] 
step getConcrete abstract : [tool] 
step make abstract : [tool] , abstract : [tool] 
step build 
step getClosure abstract : [tool] , concrete : [Train] 
step getConcrete abstract : [Train] 
step make abstract : [Train] , abstract : [Train] 
step build concrete : [Train] 
1.首先是Bind()

我们bind的是字符串,所以会调用getClosure

return function ($c) use ($abstract,$concrete){
    $method = ($abstract == $concrete) ? 'build' : 'make';
    return $c->$method($concrete);
};

但是getClosure返回的是一个闭包,闭包函数不会被立刻调用,所以我们暂时不知道$c这个参数是什么,但是我们知道$abstrac,$concrete分别对应'tool''Train'这两个字符串

2.然后是第一次make()

这是第一次调用make(),参数的值应该是'tool'getConcrete()会返回之前bind()的那个闭包,此处闭包仍然没有被执行。

isBuildable()返回true,于是我们来到第一次build(),传入的参数是之前bind()的那个闭包,if ($concrete instanceof Closure)会返回true,于是执行了这一句

return $concrete($this);

闭包终于被执行了,还记得第一步中bind()的那几个参数吗,闭包中的

return $c->$method($concrete);

就等效于

return $this->make('Train');
3.之后就是第二次make()

这次就简单了,getConcrete()会返回'Train',isBuildable()返回true,于是我们来到第二次build(),传入的参数是'Train'

4.使用反射来搞定依赖注入

build()中可以看到,因为Train这个类没有构造函数,所以直接new了一个出来并返回,如果Train这个类有构造函数,它会根据构造函数中的参数去容器中再次make()并注入到Train里面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值