IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 九、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(4) -> 正文阅读

[PHP知识库]九、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(4)

?关联阅读?

六、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(1)

七、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(2)

八、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(3)

九、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(4)

十、逐行阅读Yii2.0.43源码_Yii框架文件Container.php(5)

目录

1. isNulledParam方法

?2. getDependencies方法,返回类的依赖项

3. validateDependencies方法,检查配置参数

4. mergeDependencies方法

5. resolveDependencies方法,解析依赖

6. build方法,创建对象的核心方法

7. mergeParams方法,合并参数


1. isNulledParam方法

  • 可选参数 返回true
  • 可空参数返回 true
  • 其他返回false
    /**
     * 判断参数是 可选参数或者可空的类型参数
     */
    private function isNulledParam($param)
    {
        //1. 可选参数
        //      public function foo($str = 'optional') {
        //          ...可选参数...
        //      }
        //2. >=7.1.0 且指定为可空的类型参数
        //      public funciton tool(?int $number) {
        //          ...可空的类型参数...
        //      }
        return $param->isOptional()
            || (PHP_VERSION_ID >= 70100 && $param->getType()->allowsNull());
    }

?2. getDependencies方法,返回类的依赖项

  • 第一步:判断是否解析过,如果是直接返回,否则解析类依赖
  • 第二步:获取当前类的反射类实例,取得类构造函数的参数列表
  • 第三步:分析参数,解析参数
  • 第四步:存储解析结果并返回
    /**
     * 返回指定类的依赖项。
     */
    protected function getDependencies($class)
    {
        //判断 $_reflections中是否存在指定类
        if (isset($this->_reflections[$class])) {
            return [$this->_reflections[$class], $this->_dependencies[$class]];
        }

        $dependencies = [];
        try {
            //反射类实例,可以获取指定类的信息
            $reflection = new ReflectionClass($class);
        } catch (\ReflectionException $e) {
            throw new NotInstantiableException(
                $class,
                'Failed to instantiate component or class "' . $class . '".',
                0,
                $e
            );
        }

        //获取类$class的构造函数
        //如果$class没有构造函数,返回NULL
        $constructor = $reflection->getConstructor();

        if ($constructor !== null) {

            //$class构造函数存在,解析参数
            // $constructor->getParameters()返回一个ReflectionParameter实例数组

            foreach ($constructor->getParameters() as $param) {

                //$param->isVariadic()返回是否是可变参数
                //是返回true, 否则返回false
                // php版本 >= 5.6.0
                if (PHP_VERSION_ID >= 50600 && $param->isVariadic()) {
                    break;
                }

                // php版本 >= 8.0.0
                if (PHP_VERSION_ID >= 80000) {

                    //getType方法中,如果参数指定了类型,则返回一个 ReflectionType的实例
                    //否则,返回NULL
                    // ReflectionNamedType 继承 ReflectionType
                    $c = $param->getType();

                    $isClass = false;
                    if ($c instanceof ReflectionNamedType) {
                        //isBuiltin方法返回,当前类型是否是内建
                        // 是返回true, 否则返回false
                        //内建类型:int,float,string, bool, array,object...
                        $isClass = !$c->isBuiltin();
                    }

                } else {
                    try {
                        // 返回ReflectionClass实例
                        $c = $param->getClass();
                    } catch (ReflectionException $e) {
                        //不是可选参数和可空类型的参数
                        if (!$this->isNulledParam($param)) {
                            //进入到这里,说明指定的类不存在
                            $notInstantiableClass = null;
                            if (PHP_VERSION_ID >= 70000) {
                                $type = $param->getType();
                                //命名参数
                                if ($type instanceof ReflectionNamedType) {
                                    //参数类型名称
                                    $notInstantiableClass = $type->getName();
                                }
                            }
                            //抛出异常
                            throw new NotInstantiableException(
                                $notInstantiableClass,
                                $notInstantiableClass === null ? 'Can not instantiate unknown class.' : null
                            );
                        } else {
                            $c = null;
                        }
                    }

                    $isClass = $c !== null;
                }

                //获取类名称
                $className = $isClass ? $c->getName() : null;

                //$dependencies存储格式, xxx是Instance实例
                // [
                //      'name' => xxx
                //      'addr' => 'CHINA',
                //      'sex' => null
                // ]
                if ($className !== null) {
                    $dependencies[$param->getName()] = Instance::of($className, $this->isNulledParam($param));
                } else {
                    $dependencies[$param->getName()] = $param->isDefaultValueAvailable()
                        ? $param->getDefaultValue()
                        : null;
                }
            }
        }

        //存储 类名称 --> 类反射实例的映射
        $this->_reflections[$class] = $reflection;

        //存储 类名称 --> 类构造函数参数数组的映射
        $this->_dependencies[$class] = $dependencies;

        return [$reflection, $dependencies];
    }

3. validateDependencies方法,检查配置参数

  • 参数数组键是字符串类型 或者 整型 类型
  • 同一个数组,两个类型的键不能同时存在
    /**
     * @param array $parameters
     * @throws InvalidConfigException
     */
    private function validateDependencies($parameters)
    {
        $hasStringParameter = false;
        $hasIntParameter = false;
        
        //这个foreach遍历,检查参数的 索引类型
        //如果同一个数组中同时存在 字符串类型键和整型键,
        //将抛出参数异常
        foreach ($parameters as $index => $parameter) {
            if (is_string($index)) {
                $hasStringParameter = true;
                if ($hasIntParameter) {
                    break;
                }
            } else {
                $hasIntParameter = true;
                if ($hasStringParameter) {
                    break;
                }
            }
        }
        
        if ($hasIntParameter && $hasStringParameter) {
            throw new InvalidConfigException(
                'Dependencies indexed by name and by position in the same array are not allowed.'
            );
        }
    }

4. mergeDependencies方法

    /**
     * 用$b中值赋值给$a
     */
    private function mergeDependencies($a, $b)
    {
        foreach ($b as $index => $dependency) {
            $a[$index] = $dependency;
        }
        return $a;
    }

5. resolveDependencies方法,解析依赖

    /**
     * 解析依赖
     */
    protected function resolveDependencies($dependencies, $reflection = null)
    {
        foreach ($dependencies as $index => $dependency) {
            if ($dependency instanceof Instance) {
                if ($dependency->id !== null) {// 类名称
                    //从容器中获取类实例
                    $dependencies[$index] = $dependency->get($this);
                } elseif ($reflection !== null) {
                    //$dependency->id
                    $name = $reflection->getConstructor()->getParameters()[$index]->getName();
                    $class = $reflection->getName();
                    throw new InvalidConfigException("Missing required parameter \"$name\" when instantiating \"$class\".");
                }
            } elseif ($this->_resolveArrays && is_array($dependency)) {
                //递归解析
                $dependencies[$index] = $this->resolveDependencies($dependency, $reflection);
            }
        }

        return $dependencies;
    }

6. build方法,创建对象的核心方法

    /**
     * 创建指定类的实例
     * $class 类名称
     * $params 构造参数
     * $config
     */
    protected function build($class, $params, $config)
    {
        /* @var $reflection ReflectionClass */
        //$reflection ReflectionClass实例
        //$dependencies 一个数组, 存储了$class构造函数参数信息
        list($reflection, $dependencies) = $this->getDependencies($class);

        $addDependencies = [];
        if (isset($config['__construct()'])) {
            $addDependencies = $config['__construct()'];
            unset($config['__construct()']);
        }
        foreach ($params as $index => $param) {
            $addDependencies[$index] = $param;
        }

        // 数组参数规范检查,
        $this->validateDependencies($addDependencies);

        if ($addDependencies && is_int(key($addDependencies))) {
            //数组键是 int 类型,则转换$dependencies成为 数值数组
            $dependencies = array_values($dependencies);

            //按照顺序赋值
            $dependencies = $this->mergeDependencies($dependencies, $addDependencies);
        } else {
            //按照索引赋值
            $dependencies = $this->mergeDependencies($dependencies, $addDependencies);
            $dependencies = array_values($dependencies);
        }
        
        $dependencies = $this->resolveDependencies($dependencies, $reflection);
        //执行到这里,
        //$class的构造函数的参数对应的$dependencies已经被传递值了


        //检查类是否可实例化
        if (!$reflection->isInstantiable()) {
            throw new NotInstantiableException($reflection->name);
        }

        //无多余配置项,直接返回类实例
        if (empty($config)) {
            return $reflection->newInstanceArgs($dependencies);
        }

        //解析$config,替换$config中的配置
        $config = $this->resolveDependencies($config);
        if (!empty($dependencies) && $reflection->implementsInterface('yii\base\Configurable')) {
            // set $config as the last parameter (existing one will be overwritten)
            $dependencies[count($dependencies) - 1] = $config;
            return $reflection->newInstanceArgs($dependencies);
        }

        //给类挂载属性
        $object = $reflection->newInstanceArgs($dependencies);
        foreach ($config as $name => $value) {
            $object->$name = $value;
        }

        return $object;
    }

7. mergeParams方法,合并参数

    /**
     * 合并参数
     */
    protected function mergeParams($class, $params)
    {
        if (empty($this->_params[$class])) {
            return $params;
        } elseif (empty($params)) {
            return $this->_params[$class];
        }

        $ps = $this->_params[$class];
        foreach ($params as $index => $value) {
            $ps[$index] = $value;
        }

        return $ps;
    }

总结:

阅读了7个方法:

  • isNulledParam 判断参数
  • getDependencies 获取依赖
  • validateDependencies 检查依赖数组
  • mergeDependencies 合并依赖
  • resolveDependencies 解析依赖
  • build 创建实例的核心方法
  • mergeParams 合并参数
  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-10-18 17:08:51  更:2021-10-18 17:10:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 13:53:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计