入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

yii2框架-yii2自身的自动加载(三)

创建时间:2016-05-23 投稿人: 浏览次数:2842
上一节说完了composer的自动加载,下面我们来说一下yii2自身的自动加载。

在我们的入口文件,例如index.php,代码如下:

<?php

// comment out the following two lines when deployed to production

defined("YII_DEBUG") or define("YII_DEBUG", true);
defined("YII_ENV") or define("YII_ENV", "dev");

require(__DIR__ . "/../vendor/autoload.php");

require(__DIR__ . "/../vendor/yiisoft/yii2/Yii.php");

$config = require(__DIR__ . "/../config/web.php");

(new yiiwebApplication($config))->run();

我们可以注意到require(__DIR__ . "/../vendor/yiisoft/yii2/Yii.php"),将yii2的核心的函数包含进去,下面看看Yii.php的代码:

<?php
/**
 * Yii bootstrap file.
 *
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

require(__DIR__ . "/BaseYii.php");

/**
 * Yii is a helper class serving common framework functionalities.
 *
 * It extends from [[yiiBaseYii]] which provides the actual implementation.
 * By writing your own Yii class, you can customize some functionalities of [[yiiBaseYii]].
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Yii extends yiiBaseYii
{
}

spl_autoload_register(["Yii", "autoload"], true, true);
Yii::$classMap = require(__DIR__ . "/classes.php");
Yii::$container = new yiidiContainer();

首先包含BaseYii.php这个基础的yii文件,然后类Yii继承包含的Yii文件,命名空间是yiiBaseYii,同时通过spl_autoload_register注册一个自动加载函数,这个函数是本类的autoload()函数,这些函数是在yiiBaseYii中定义,而Yii类又继承yiiBaseYii,所以Yii类相当于定义这些属性和方法。

而Yii::$classMap = require(__DIR__ . "/classes.php")这一句定义了命名空间与实际路径的映射关系,将返回一个数组的形式,保存在一个静态的变量中,那么这个变量有什么用呢?

下面我们再来看看spl_autoload_register注册的autoload()函数,在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?");
        }
    }

其中参数$className代表的是命名空间的类名,这个函数首先根据类名$className从$classMap是否可以找到对应设置的映射关系,如果找到对应的映射关系,就把文件对应的路径解释出来,赋值变量$classFile,如果找不到对应的映射关系,则将这个命名空间类执行:
$classFile = static::getAlias("@" . str_replace("\", "/", $className) . ".php"
这句代码就是通过别名的方式来映射定义路径,比如:new appcontrollersUser,这个在$classMap肯定是找不到对应的关系的,所以这句代码会把appcontrollersUser先替换成@app/controllers/User,然后再通过static::getAlias("@app/controllers/User")解释别名,找到对应的实际文件路径,因为@app在配置文件中已经定义或者默认定义别名,getAlias()会负责解释,当然需要在@app下建立controllers的文件夹等,并将解释路径的值赋值变量$classFile,最后将这个路径包含进来。

所以总结一点:
我们可以在定义了别名的文件夹下@xxx,再建立文件夹aaa,然后定义文件bbb.php,那么在bbb.php的文件的命名空间就是xxxaaa,这个文件的类名就是bbb。那么我们就可以在任何的地方直接用 new xxxaaabb()的形式类创建实例。发生的过程大概就是这样子:
a)因为我们在入口文件首先注册composer的自动加载函数,放在spl的堆栈中

b)接着,我们又注册yii2自身的自动加载函数,放在spl的堆栈中,根据栈的后入先出的原则,yii2注册的函数将放在composer注册函数的前面,如果要用自动加载函数的话,首先用yii2自身注册的。

c)所以当我们 new xxxaaabb 的时候,首先会从堆栈中调用yii2自身注册的autoload()函数,查找在yii2的本身是否存在对应的映射关系,如果找到,就直接包含文件进来,并实例化。如果找不到,再到yii2定义的别名的文件夹下面找,如果找到,就直接包含文件进来,并实例化。如果在yii注册的函数里都找不到,则接着调用spl堆栈的第二个自动函数,即composer自定义的autload()函数,按照函数定义的方式一直往下找,知道找到为止.如果确实找不到会返回错误。

声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。