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()函数,按照函数定义的方式一直往下找,知道找到为止.如果确实找不到会返回错误。
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()函数,按照函数定义的方式一直往下找,知道找到为止.如果确实找不到会返回错误。
相关文章推荐
- 2017_01_02_1_别名
- 2017_01_02_1_源码阅读--BaseYii.php
- 20150112--抽象类+接口+重载+自动加载机制-01
- 2017-01-02 上课类容
- 2017_01_02_1_静态绑定
- 获取一个年份、月份、一段时间的年月份sql,例如从某年到今年的时间段2017-01、2017-02
- 02图片加载_01_Android_Universal_Image_Loader
- 20150112--抽象类+接口+重载+自动加载机制-02
- 2017_01_03_02_路由
- Redhat Linux AS4中移动硬盘自动加载后中文内容为乱码?
- 第十二节--类的自动加载
- 第十二节 类的自动加载 [12]
- php基础知识:类与对象(2) 自动加载对象
- [07-01-06]打开某IT技术问答网站时自动下载文件sinze.exe/Trojan-Dropper.Win32.Agent.awq
- ajax自动加载blogjava和博客园的rss
- php基础知识:类与对象(2) 自动加载对象
- 第十二节 类的自动加载 [12]
- Spring中自动加载Hibernate配置文件
- 自动生成AJAX加载图片
- 从XML文件自动加载下拉列表框