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

 关联阅读 

六、逐行阅读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)

目录

一、属性

二、方法


一、属性

学习了6个属性

$_singletons: 

保存了单例对象数组

$_definitions

当创建对象的时候,根据其中的值,类型不同,选择不同的创建方式

$_params

构造函数参数

$_reflections

存储ReflectionClass实例

$_dependencies

存储依赖数据

$_resolveArrays

是否要尝试解析$_dependencies中的元素

/**
     * 保存了单例对象数组
     */
    private $_singletons = [];


    /**
     * 对象定义数组
     * 当创建对象的时候,根据其中的值,类型不同
     * 选择不同的创建方式
     * $_definitions看上去类似下面这样
     * $_definitions = [
     *      'yii\db\Connection' => ['yii\db\Connection', 'connect'],
     *      'app\product\Order' => $order,//一个order实例
     *      'app\admin' => function(){return new Admin()},
     *      'role' => ['class' => 'app/Role', ...],
     *      ....
     * ]
     */
    private $_definitions = [];


    /**
     * 构造函数参数
     */
    private $_params = [];


    /**
     * 存储ReflectionClass实例
     */
    private $_reflections = [];

    /**
     * 存储依赖数据
     */
    private $_dependencies = [];


    /**
     * 是否要尝试解析$_dependencies中的元素
     */
    private $_resolveArrays = false;

二、方法

  • get 返回一个对象实例

1)BaseYii::createObject方法实质调用的是这个方法

2)BaseYii::createObject创建一个对象实例:

  • 基于 类名称
  • 基于配置数组
  • 基于php调用 
/**
     * 返回一个对象实例
     * BaseYii::createObject方法实质调用的是这个方法
     * BaseYii::createObject创建一个对象实例:
     *      1. 基于 类名称
     *      2. 基于配置数组
     *      3. 基于php调用
     *
     * $class 类实例,名称或者别名
     * $params 构造函数所需的参数
     * $config 用来初始化对象的属性
     */
    public function get($class, $params = [], $config = [])
    {
        if ($class instanceof Instance) {
            $class = $class->id;
        }

        //1. 单例数组中存储有,直接返回
        if (isset($this->_singletons[$class])) {
            // singleton
            return $this->_singletons[$class];
        } elseif (!isset($this->_definitions[$class])) {
            //如果$_singletons没有且也没有定义,创建返回
            //这里创建的对象不是单例,每一次都会是一个新的实例
            return $this->build($class, $params, $config);
        }

        $definition = $this->_definitions[$class];

        if (is_callable($definition, true)) {
            //这里is_callable函数的第二个参数是true,意味着,
            //$definition只要符合是一个php调用的格式就可以了
            //,不一定真的可以调用,
            // $definition 可以是一个字符串,匿名函数,
            //两个元素的给关联的数组,第一个元素是对象或者字符串,
            //第二个元素是字符串

            //解析参数
            $params = $this->resolveDependencies($this->mergeParams($class, $params));

            //如果可以调用,应当返回一个实例
            $object = call_user_func($definition, $this, $params, $config);

        } elseif (is_array($definition)) {
            $concrete = $definition['class'];
            unset($definition['class']);

            $config = array_merge($definition, $config);
            $params = $this->mergeParams($class, $params);

            if ($concrete === $class) {
                $object = $this->build($class, $params, $config);
            } else {
                //递归调用
                $object = $this->get($concrete, $params, $config);
            }

        } elseif (is_object($definition)) {
            return $this->_singletons[$class] = $definition;
        } else {
            throw new InvalidConfigException('Unexpected object definition type: ' . gettype($definition));
        }

        if (array_key_exists($class, $this->_singletons)) {
            // 存在则赋值新值,
            //这里注意 isset 和 array_key_exists的区别
            //这个方法上面代码判断使用 isset($this->_singletons[$class])
            //也就是说当 $this->_singletons[$class] 为null时,
            // isset($this->_singletons[$class])返回false,而
            // array_key_exists($class, $this->_singletons)返回true,
            //这里会重新赋值
            $this->_singletons[$class] = $object;
        }

        return $object;
    }

总结:

1. 阅读了Container.php中6个属性

2.重点阅读了get方法,整个方法主要分为7个分支步骤完成:

  • 第一步:判断 $_singletons数组中是否存在对应实例,存在立即返回
  • 第二步:判断$_definitions数组中是不是存在,不存在,就创建一个实例返回
  • 第三步:如果$_definitions数组中存在,则取出对应数据,如果值是一个php调用格式,则尝试执行call_user_func,尝试获取一个实例
  • 第四步:如果是一个配置数组,则取出其中的class键对应的数据与当前$class值比较,完全相同,则创建一个实例
  • 第五步:如果不同,递归调用get,重新走这7个步骤,获得一个实例
  • 第六步:如果是一个实例,则赋值给单例数组,并返回
  • 第七步:以上都不符合,抛出异常

扩展学习

 1. isset和array_key_exists的区别

  • isset是语言构造器,不是一个函数,array_key_exists是函数
  • isset和array_key_exists都可以用来检测数组中是否存在对应键,不同的是,当数组中某个键对应的值为NULL时, isset 返回 false, 而array_key_exists返回true
  • isset可以用来检测多维数组,而array_key_exists检测一维数组
  • 执行效率上isset优于array_key_exists
<?php

$arr = [
    'aa' => 'a',
    'bb' => '',
    'cc' => false,
    'dd' => NULL,
    'ee' => 0,
];

var_dump(isset($arr['aa']));// true
var_dump(isset($arr['bb']));// true
var_dump(isset($arr['cc']));// true
var_dump(isset($arr['dd']));// false
var_dump(isset($arr['ee']));// true

var_dump(array_key_exists('aa', $arr));// true
var_dump(array_key_exists('bb', $arr));// true
var_dump(array_key_exists('cc', $arr));// true
var_dump(array_key_exists('dd', $arr));// true
var_dump(array_key_exists('ee', $arr));// true

 2. is_callable函数 验证变量的内容是否可以作为函数调用

is_callable有三个参数,重点研究,第二个参数的作用

当第二个参数为true时,只检查参数1是否符合php调用的格式,满足即可返回true

当第二个参数为false时,同时检查参数1是否符合php调用的格式和是否真的可以调用,同时满足返回true

<?php

//注意看一下区别

var_dump(is_callable('aa', true));// true
var_dump(is_callable(function(){}, true)); //true
var_dump(is_callable(['aa', 'bb'], true)); // true
var_dump(is_callable(['aa' => 'bb'], true));// false

var_dump(is_callable('aa', false));// false
var_dump(is_callable(function(){}, false)); //true
var_dump(is_callable(['aa', 'bb'], false)); // false
var_dump(is_callable(['aa' => 'bb'], false));// false

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值