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
PHP5与MySQL数据库操作常用代码 收集
Mar 21 PHP
ubuntu 编译安装php 5.3.3+memcache的方法
Aug 05 PHP
基于magic_quotes_gpc与magic_quotes_runtime的区别与使用介绍
Apr 22 PHP
探讨php中防止SQL注入最好的方法是什么
Jun 10 PHP
php 批量替换html标签的实例代码
Nov 26 PHP
php针对cookie操作的队列操作类实例
Dec 10 PHP
百万级别知乎用户数据抓取与分析之PHP开发
Sep 28 PHP
php+ajax实现无刷新数据分页的办法
Nov 02 PHP
PHP创建PowerPoint2007文档的方法
Dec 10 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
Jan 05 PHP
PHP实现的大文件切割与合并功能示例
Apr 10 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的超级变量$_GET获取HTML表单(Form) 数据
2011/05/07 PHP
解析yii数据库的增删查改
2013/06/20 PHP
浅析PHP中的UNICODE 编码与解码
2013/06/29 PHP
PHP统计目录大小的自定义函数分享
2014/11/18 PHP
PHP  实现等比压缩图片尺寸和大小实例代码
2016/10/08 PHP
javascript 计算两个整数的百分比值
2009/12/26 Javascript
JQuery中getJSON的使用方法
2010/12/13 Javascript
JavaScript高级程序设计(第3版)学习笔记13 ECMAScript5新特性
2012/10/11 Javascript
JavaScript 垃圾回收机制分析
2013/10/10 Javascript
手机平板等移动端适配跳转URL的js代码
2014/01/25 Javascript
jQuery实现简单网页遮罩层/弹出层效果兼容IE6、IE7
2014/06/16 Javascript
jQuery中:last-child选择器用法实例
2014/12/31 Javascript
jQuery判断数组是否包含了指定的元素
2015/03/10 Javascript
JavaScript自定义等待wait函数实例分析
2015/03/23 Javascript
Bootstrap零基础学习第一课之模板
2016/07/18 Javascript
浅谈在koa2中实现页面渲染的全局数据
2017/10/09 Javascript
Angular8路由守卫原理和使用方法
2019/08/29 Javascript
JS绘图Flot如何实现动态可刷新曲线图
2020/10/16 Javascript
[01:02:03]2014 DOTA2华西杯精英邀请赛 5 24 NewBee VS VG
2014/05/26 DOTA
[01:23]2014DOTA2国际邀请赛 球迷无处不在Ti现场世界杯受关注
2014/07/10 DOTA
python抓取豆瓣图片并自动保存示例学习
2014/01/10 Python
python通过自定义isnumber函数判断字符串是否为数字的方法
2015/04/23 Python
Python读大数据txt
2016/03/28 Python
Python处理文本换行符实例代码
2018/02/03 Python
python opencv 读取本地视频文件 修改ffmpeg的方法
2019/01/26 Python
Python3实现的旋转矩阵图像算法示例
2019/04/03 Python
PyCharm 解决找不到新打开项目的窗口问题
2021/01/15 Python
利用纯html5绘制出来的一款非常漂亮的时钟
2015/01/04 HTML / CSS
HTML5实现视频弹幕功能
2019/08/09 HTML / CSS
神路信息Java面试题目
2013/03/31 面试题
软件配置管理有什么好处
2015/04/15 面试题
社区健康教育实施方案
2014/03/18 职场文书
民事赔偿协议书
2014/11/02 职场文书
基层工作经历证明
2015/06/19 职场文书
导游词之吉林花园山
2019/10/17 职场文书
详解PHP用mb_string处理windows中文字符
2021/05/26 PHP