tp6实现DI(依赖注入)

1.(new App())->http 

调用无法调用的属性(不存在或者是非public),会触发__get()魔术方法.因为App继承了Container类,该方法在Container中

    #1.触发
    public function __get($name)
    {
        return $this->get($name);
    }

    #2.
    public function get($abstract)
    {
        if ($this->has($abstract)) {            //是否在App->bind或Container->instances中
            return $this->make($abstract);      //创建实例化对象  
        }

        throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);
    }

2.通过make()方法实例化类

    public function make(string $abstract, array $vars = [], bool $newInstance = false)
    {
        $abstract = $this->getAlias($abstract);            //通过别名,获取别名绑定的类
        //省略部分代码
        $object = $this->invokeClass($abstract, $vars);    //重点
        if (!$newInstance) {
            $this->instances[$abstract] = $object;
        }
        return $object;
    }

3.

    public function invokeClass(string $class, array $vars = [])
    {
        try {
            $reflect = new ReflectionClass($class);            //映射类
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException('class not exists: ' . $class, $class, $e);
        }

        $constructor = $reflect->getConstructor();            //反射了类的构造函数
        $args = $constructor ? $this->bindParams($constructor, $vars) : [];
        $object = $reflect->newInstanceArgs($args);            //通过参数实例化对象
        return $object;
    }

4.绑定参数

    public function bindParams(ReflectionFunctionAbstract $reflect, array $vars = []): array
    {
        if ($reflect->getNumberOfParameters() == 0) {
            return [];
        }
        reset($vars);                   //将数组的内部指针重置到数组中的第一个元素
        $type   = key($vars) === 0 ? 1 : 0;     //关联数组还是下标数组
        $params = $reflect->getParameters();    //获取类方法的参数,这里传的构造函数的参数
        $args   = [];
        foreach ($params as $param) {
            $name           = $param->getName();
            $lowerName      = Str::snake($name); //驼峰转下划线
            //获取参数的类型 function someFunction(int $param) 为int
            $reflectionType = $param->getType(); 
            //$reflectionType->isBuiltin()检查它是否是内置类型
            if ($reflectionType && $reflectionType->isBuiltin() === false) {
                $args[] = $this->getObjectParam($reflectionType->getName(), $vars);
            } elseif (1 == $type && !empty($vars)) {
                $args[] = array_shift($vars);
            } elseif (0 == $type && array_key_exists($name, $vars)) {
                $args[] = $vars[$name];
            } elseif (0 == $type && array_key_exists($lowerName, $vars)) {
                $args[] = $vars[$lowerName];
            } elseif ($param->isDefaultValueAvailable()) {
                $args[] = $param->getDefaultValue();
            } else {
                throw new InvalidArgumentException('method param miss:' . $name);
            }
        }

        return $args;
    }

5.获取对象的参数

    protected function getObjectParam(string $className, array &$vars)
    {
        $array = $vars;
        $value = array_shift($array);

        if ($value instanceof $className) {
            $result = $value;
            array_shift($vars);
        } else {
            $result = $this->make($className);  //实例化对象
        }

        return $result;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值