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 相关文章推荐
多文件上载系统完整版
Oct 09 PHP
xml+php动态载入与分页
Oct 09 PHP
php str_replace的替换漏洞
Mar 15 PHP
php下获取客户端ip地址的函数
Mar 15 PHP
浅析PHP中Collection 类的设计
Jun 21 PHP
php内嵌函数用法实例
Mar 20 PHP
PHP加密解密类实例分析
Apr 20 PHP
PHP5.2下preg_replace函数的问题
May 08 PHP
ThinkPHP3.2.2实现持久登录(记住我)功能的方法
May 16 PHP
PHP 芝麻信用接入的注意事项
Dec 01 PHP
php curl上传、下载、https登陆实现代码
Jul 23 PHP
使用PHPStorm+XDebug搭建单步调试环境
Nov 19 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版(2)
2006/10/09 PHP
《PHP编程最快明白》第七讲:php图片验证码与缩略图
2010/11/01 PHP
PHP中文分词 自动获取关键词介绍
2012/11/13 PHP
php输出echo、print、print_r、printf、sprintf、var_dump的区别比较
2013/06/21 PHP
php的zip解压缩类pclzip使用示例
2014/03/14 PHP
PHP错误Allowed memory size of 67108864 bytes exhausted的3种解决办法
2014/07/28 PHP
PHP实现图片的等比缩放和Logo水印功能示例
2017/05/04 PHP
php简单中奖算法(实例)
2017/08/15 PHP
PHP getName()函数讲解
2019/02/03 PHP
Yii框架中使用PHPExcel的方法分析
2019/07/25 PHP
Laravel Eloquent分表方法并使用模型关联的实现
2019/11/25 PHP
JS远程获取网页源代码实例
2013/09/05 Javascript
使用js在页面中绘制表格核心代码
2013/09/16 Javascript
nodejs npm install全局安装和本地安装的区别
2014/06/05 NodeJs
JS实现点击按钮控制Div变宽、增高及调整背景色的方法
2015/08/05 Javascript
如何在JS中实现相互转换XML和JSON
2016/07/19 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
详解Angular Karma测试的持续集成实践
2019/11/15 Javascript
jQuery实现轮播图效果demo
2020/01/11 jQuery
vue中keep-alive、activated的探讨和使用详解
2020/07/26 Javascript
element-ui和vue表单(对话框)验证提示语(残留)清除操作
2020/09/11 Javascript
Python自定义进程池实例分析【生产者、消费者模型问题】
2016/09/19 Python
Python3 Random模块代码详解
2017/12/04 Python
PyTorch CNN实战之MNIST手写数字识别示例
2018/05/29 Python
Python实现的多进程和多线程功能示例
2018/05/29 Python
python数字类型math库原理解析
2020/03/02 Python
用Python生成HTML表格的方法示例
2020/03/06 Python
Python+unittest+requests 接口自动化测试框架搭建教程
2020/10/09 Python
日本最大的购物网站乐天市场国际版:Rakuten Global Market(支持中文)
2020/02/03 全球购物
拓展策划方案
2014/06/03 职场文书
县委常委班子专题民主生活会查摆问题及整改措施
2014/09/27 职场文书
法制主题班会教案
2015/08/13 职场文书
四年级数学教学反思
2016/02/16 职场文书
Vue详细的入门笔记
2021/05/10 Vue.js
vue elementUI表格控制对应列
2022/04/13 Vue.js
Java Spring Boot请求方式与请求映射过程分析
2022/06/25 Java/Android