您的位置:首页 > 其它

2017_01_02_1_类自动加载

2017-01-02 12:10 330 查看
类自动加载(Autoloading)

Yii 依靠类自动加载机制来定位和包含所需的类文件。

它提供一个高性能且完美支持PSR-4 标准 (中文汉化)的自动加载器。

该自动加载器会在引入框架文件 Yii.php 时安装好。

使用 Yii 自动加载器

要使用 Yii 的类自动加载器,你需要在创建和命名类的时候遵循两个简单的规则:

每个类都必须置于命名空间之下 (比如 foo\bar\MyClass)。

每个类都必须保存为单独文件,且其完整路径能用以下算法取得:

// $className 是一个开头包含反斜杠的完整类名

$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');

举例来说,若某个类名为 foo\bar\MyClass,对应类的文件路径别名会是 @foo/bar/MyClass.php。

为了让该别名能被正确解析为文件路径,@foo 或 @foo/bar 中的一个必须是根别名。

在我们的入口文件,例如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 yii\web\Application($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 [[\yii\BaseYii]] which provides the actual implementation.

     * By writing your own Yii class, you can customize some functionalities of [[\yii\BaseYii]].

     *

     * @author Qiang Xue <qiang.xue@gmail.com>

     * @since 2.0

     */  

    class Yii extends \yii\BaseYii  

    {  

    }  

      

    spl_autoload_register(['Yii', 'autoload'], true, true);  

    Yii::$classMap = require(__DIR__ . '/classes.php');  

    Yii::$container = new yii\di\Container();  

首先包含BaseYii.php这个基础的yii文件,然后类Yii继承包含的Yii文件,命名空间是\yii\BaseYii,同时通过spl_autoload_register注册一个自动加载函数,这个函数是本类的autoload()函数,这些函数是在\yii\BaseYii中定义,而Yii类又继承\yii\BaseYii,所以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 \app\controllers\User,这个在$classMap肯定是找不到对应的关系的,所以这句代码会把\app\controllers\User先替换成@app/controllers/User,然后再通过static::getAlias('@app/controllers/User')解释别名,找到对应的实际文件路径,因为@app在配置文件中已经定义或者默认定义别名,getAlias()会负责解释,当然需要在@app下建立controllers的文件夹等,并将解释路径的值赋值变量$classFile,最后将这个路径包含进来。

所以总结一点:

我们可以在定义了别名的文件夹下@xxx,再建立文件夹aaa,然后定义文件bbb.php,那么在bbb.php的文件的命名空间就是xxx\aaa,这个文件的类名就是bbb。那么我们就可以在任何的地方直接用 new \xxx\aaa\bbb()的形式类创建实例。发生的过程大概就是这样子:

a)因为我们在入口文件首先注册composer的自动加载函数,放在spl的堆栈中

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

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

        

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: