Yii2框架类自动加载机制实例分析


Posted in PHP onMay 02, 2018

本文实例讲述了Yii2框架类自动加载机制。分享给大家供大家参考,具体如下:

在yii中,程序中需要使用到的类无需事先加载其类文件,在使用的时候才自动定位类文件位置并加载之,这么高效的运行方式得益于yii的类自动加载机制。

Yii的类自动加载实际上使用的是PHP的类自动加载,所以先来看看PHP的类自动加载。在PHP中,当程序中使用的类未加载时,在报错之前会先调用魔术方法__autoload(),所以我们可以重写__autoload()方法,定义当一个类找不到的时候怎么去根据类名称找到对应的文件并加载它。其中__autoload()方法被称为类自动加载器。当我们需要多个类自动加载器的时候,我们可以使用spl_autoload_register()方法代替__autoload()来注册多个类自动加载器,这样就相当于有多个__autoload()方法。spl_autoload_register()方法会把所有注册的类自动加载器存入一个队列中,你可以通过设置它的第三个参数为true来指定某个加载器放到队列的最前面以确保它最先被调用。Yii的类自动加载机制就是基于spl_autoload_register()方法的。

Yii的类自动加载机制要从它的入口文件index.php说起了,该文件源码如下:

<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);//运行模式
defined('YII_ENV') or define('YII_ENV', 'dev');//运行环境
require(__DIR__ . '/../../vendor/autoload.php');//composer的类自动加载文件
require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');//yii的工具类文件(包含了yii类自动加载)
require(__DIR__ . '/../../common/config/bootstrap.php');//主要用于执行一些yii应用引导的代码
require(__DIR__ . '/../config/bootstrap.php');
$config = yii\helpers\ArrayHelper::merge(
  require(__DIR__ . '/../../common/config/main.php'),
  require(__DIR__ . '/../../common/config/main-local.php'),
  require(__DIR__ . '/../config/main.php'),
  require(__DIR__ . '/../config/main-local.php')
);
(new yii\web\Application($config))->run();

文件中第4、5行代码分别引入了composer的类自动加载文件和yii的工具类文件Yii.php,Yii.php文件源码如下:

require(__DIR__ . '/BaseYii.php');
class Yii extends \yii\BaseYii
{
}
spl_autoload_register(['Yii', 'autoload'], true, true);//注册yii的类自动加载器
Yii::$classMap = require(__DIR__ . '/classes.php');//引入类名到类文件路径的映射
Yii::$container = new yii\di\Container();

这个文件定义了Yii类继承自\yii\BaseYii,代码的第6行引入了classes.php文件,该文件源码:

return [
 'yii\base\Action' => YII2_PATH . '/base/Action.php',
 'yii\base\ActionEvent' => YII2_PATH . '/base/ActionEvent.php',
  ....//省略n多元素
 'yii\widgets\Pjax' => YII2_PATH . '/widgets/Pjax.php',
 'yii\widgets\PjaxAsset' => YII2_PATH . '/widgets/PjaxAsset.php',
 'yii\widgets\Spaceless' => YII2_PATH . '/widgets/Spaceless.php',
];

通过查看其源码可以看到,这个文件返回了一个从类名称到类文件路径的映射数组。这个数组被赋值给Yii::$classMap。代码的第7行调用了spl_autoload_register()方法注册了一个类自动加载器,这个类加载器为Yii::autoload(),这就是yii的类加载器了。同时这里通过把spl_autoload_register()方法第三个参数赋值为true,把yii的类加载器放在了加载器队列的最前面,所以当访问一个未加载的类的时候,yii的类自动加载器会最先被调用。

下面我们就来看看yii的类自动加载器Yii::autoload()到底做了些什么,这个方法实际上在yii\BaseYii类中,源码如下:

/**
 * 类自动加载器
 * @param type $className:要加载的类的名称
 * @return type
 * @throws UnknownClassException
 */
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?");
  }
}

这个方法首先会根据需要加载的类的名称去Yii::$classMap这个映射数组中查找,若存在则引入对应的类文件,不存在则进行别名解析得到完整文件路径,这里也说明若使用的类不在YII::$classMap中事先定义,则类名必须以有效的根别名打头,否则无法找到对应文件。

就这样,在yii中无需在程序中事先加载一大堆可能会使用到的类文件,当使用到某个类的时候,yii的类自动加载器就会自动进行加载了,高效又便捷!

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
修改php.ini实现Mysql导入数据库文件最大限制的修改方法
Dec 11 PHP
40个迹象表明你还是PHP菜鸟
Sep 29 PHP
php allow_url_include的应用和解释
Apr 22 PHP
php 中英文语言转换类
Sep 07 PHP
关于mysql字符集设置了character_set_client=binary 在gbk情况下会出现表描述是乱码的情况
Jan 06 PHP
php中使用preg_match_all匹配文章中的图片
Feb 06 PHP
PHP人民币金额数字转中文大写的函数代码
Feb 27 PHP
PHP生成不重复标识符的方法
Nov 21 PHP
WordPress中对访客评论功能的一些优化方法
Nov 24 PHP
CI框架中$this-&gt;load-&gt;library()用法分析
May 18 PHP
微信开发之php表单微信中自动提交两次问题解决办法
Jan 08 PHP
老生常谈PHP中的数据结构:DS扩展
Jul 17 PHP
PHP通过bypass disable functions执行系统命令的方法汇总
May 02 #PHP
购物车实现的几种方式优缺点对比
May 02 #PHP
PHP生成(支持多模板)二维码海报代码
Apr 30 #PHP
PHP实现的猴王算法(猴子选大王)示例
Apr 30 #PHP
PHP+MySQL高并发加锁事务处理问题解决方法
Apr 30 #PHP
PHP使用file_get_contents发送http请求功能简单示例
Apr 29 #PHP
PHP实现通过strace定位故障原因的方法
Apr 29 #PHP
You might like
PHP动态编译出现Cannot find autoconf的解决方法
2014/11/05 PHP
深入解析Laravel5.5中的包自动发现Package Auto Discovery
2017/09/13 PHP
YUI 读码日记之 YAHOO.util.Dom - Part.1
2008/03/22 Javascript
JavaScript Memoization 让函数也有记忆功能
2011/10/27 Javascript
不使用XMLHttpRequest实现异步加载 Iframe和script
2012/10/29 Javascript
jQuery实现tab选项卡效果的方法
2015/07/08 Javascript
简单实现兼容各大浏览器的js复制内容到剪切板
2015/09/09 Javascript
BootStrap Datetimepicker 汉化的实现代码
2017/02/10 Javascript
jQuery仿IOS弹出框插件
2017/02/18 Javascript
AngularJS中控制器函数的定义与使用方法示例
2017/10/10 Javascript
实现div滚动条默认最底部以及默认最右边的示例代码
2017/11/15 Javascript
微信小程序支付功能 php后台对接完整代码分享
2018/06/12 Javascript
javascript的this关键字详解
2019/05/20 Javascript
JS实现网页时钟特效
2020/03/25 Javascript
WebStorm中如何将自己的代码上传到github示例详解
2020/10/28 Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
2020/11/09 Javascript
用webAPI实现图片放大镜效果
2020/11/23 Javascript
[02:56]DOTA2英雄基础教程 巨魔战将
2013/12/10 DOTA
打印出python 当前全局变量和入口参数的所有属性
2009/07/01 Python
python的id()函数介绍
2013/02/10 Python
十个Python程序员易犯的错误
2015/12/15 Python
浅谈python字符串方法的简单使用
2016/07/18 Python
利用Python将数值型特征进行离散化操作的方法
2018/11/06 Python
使用Python画股票的K线图的方法步骤
2019/06/28 Python
python中sort和sorted排序的实例方法
2019/08/26 Python
丝芙兰新加坡官网:Sephora新加坡
2018/12/04 全球购物
博朗(Braun)俄罗斯官方商店:德国小家电品牌
2019/09/24 全球购物
乌克兰最大的家用电器和电子产品连锁店:Eldorado
2019/10/02 全球购物
护士自我鉴定总结
2014/03/24 职场文书
相亲活动方案
2014/08/26 职场文书
乡镇党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
受资助学生感谢信
2015/01/21 职场文书
交警失职检讨书
2015/01/26 职场文书
2015年仓库管理员工作总结
2015/04/21 职场文书
浪漫的婚礼主持词
2015/06/30 职场文书
2016年教师学习廉政准则心得体会
2016/01/20 职场文书