❥(^_-) Yii2框架源码解析之全局辅助类Yii.php

源码分析

我们在入口文件里面,已经看到引入了Yii.php,那么在这里我们把源码贴出来:

<?php

require __DIR__ . '/BaseYii.php';

class Yii extends \yii\BaseYii
{
}

//Yii全局辅助类,没啥可说的。

//注册自动加载,为Yii里面的autoload方法。(当然,autoload方法存在于Yii的基类:\yii\BaseYii)
spl_autoload_register(['Yii', 'autoload'], true, true);

// 自动加载的所有类的全局树。
Yii::$classMap = require __DIR__ . '/classes.php';

// 实例化一个容器,作为当前应用的容器。
Yii::$container = new yii\di\Container();

首先,我们引入了辅助类的基类BaseYii.php (因为这个时候,自动加载还没注册,所以只能手动引入),然后注册自动加载。我们接下来讲一下BaseYii.php这个类。这个类主要实现的事情有:

1. 定义一些全局常量。

2. 类的自动加载

3. 路径别名的设置和获取。

4. 创建对象并注入到当前容器。

5. 不同级别日志的记录功能。

6. 语言翻译。

7. 对象属性的初始设置。

当引入yii.php的时候,根据程序执行来看,做的事情有:定义常量和自动加载。我们这里顺便把BaseYii.php的所有支持的功能都列了出来。这里主要讲自动加载、对象的属性设置、以及创建类三个方法。


自动加载:

public static function autoload($className)
    {
        if (isset(static::$classMap[$className])) {
            $classFile = static::$classMap[$className];
            if ($classFile[0] === '@') {
                $classFile = static::getAlias($classFile);
            }
        } elseif (strpos($className, '\\') !== false) {
            $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false);
            if ($classFile === false || !is_file($classFile)) {
                return;
            }
        } else {
            return;
        }

        include $classFile;

        if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) {
            throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?");
        }
    }


public static function getAlias($alias, $throwException = true)
    {
        // 如果第一个字符不是@符号,代表不是Yii框架内部的命名空间,直接返回。
        if (strncmp($alias, '@', 1)) {
            // not an alias
            return $alias;
        }

        // 获取根命名空间
        $pos = strpos($alias, '/');
        $root = $pos === false ? $alias : substr($alias, 0, $pos);

        // 根命名空间必须提前注册到全局注册树上。如果根命名空间不存在就直接返回false
        if (isset(static::$aliases[$root])) {
            if (is_string(static::$aliases[$root])) {
                return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
            }


            foreach (static::$aliases[$root] as $name => $path) {
                if (strpos($alias . '/', $name . '/') === 0) {
                    return $path . substr($alias, strlen($name));
                }
            }
        }

        if ($throwException) {
            throw new InvalidArgumentException("Invalid path alias: $alias");
        }

        return false;
    }

首先,autoload方法已经在Yii.php中通过spl_autoload_register()函数注册。autoload()方法存在一个参数$className,就是完整的类名称(包含命名空间),$className是php自动传入的,我们不需要做处理。

$classMap是BaseYii.php的静态属性,它是自动加载完毕的类的全局树。数组键是类名(不带前导反斜杠),数组值是对应的类文件路径。getAlias()用来获取真实类文件路径。

最后引入文件。


创建对象:

public static function createObject($type, array $params = [])
    {
        // 创建对象,并将其注入当前应用的容器中。

        if (is_string($type)) {
            return static::$container->get($type, $params);
        }

        if (is_callable($type, true)) {
            return static::$container->invoke($type, $params);
        }

        if (!is_array($type)) {
            throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
        }

        if (isset($type['__class'])) {
            $class = $type['__class'];
            unset($type['__class'], $type['class']);
            return static::$container->get($class, $params, $type);
        }

        if (isset($type['class'])) {
            $class = $type['class'];
            unset($type['class']);
            return static::$container->get($class, $params, $type);
        }

        throw new InvalidConfigException('Object configuration must be an array containing a "class" or "__class" element.');
    }

createObject其实就是new的增强版,他可以根据配置创建一个对象。

第一个参数$type支持字符串、数组、回调函数三种类型。如果type是一个数组,该数组必须包括"__class"或者"class"键。该键对应的值是需要创建的对象对应的类名称。数组里面其他的参数是这个类的属性的初始值的设置。$params则是该类的构造方法所需要的参数。如果type是字符串,则是一个类名称,如果是回调函数,则直接出发回调。$params就是回调函数所需参数。

具体创建对象的实现逻辑,我会在后面的容器章节进行讲解。


设置对象初始属性:

public static function configure($object, $properties)
    {
        foreach ($properties as $name => $value) {
            $object->$name = $value;
        }
        return $object;
    }

这个方法第一个参数是需要设置属性的对象, 第二个参数是需要设置的对象的属性(键值对形式的数组)。代码及其简单,为什么单独拿出来讲呢?因为这里涉及到php魔术方法__set()的一个触发场景。

__set()当设置一个没有访问权限的属性值,或者是设置不存在的属性值的时候会触发。但是yii2源码中,为了满足编辑器的友好展示,使用注释的方式表示类的属性。(这种方式其实并没什么卵用,相当于没写)例如

/**
 * @property array $prop;
 * Class A
 */
class A
{

}

这样可以触发__set()和__get()方法。因为属性$prop不存在呀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值