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 模拟登陆MSN并获得用户信息
May 16 PHP
PHP 开发环境配置(测试开发环境)
Apr 28 PHP
PHP中去掉字符串首尾空格的方法
May 19 PHP
基于PHPExcel的常用方法总结
Jun 13 PHP
解析func_num_args与func_get_args函数的使用
Jun 24 PHP
解析link_mysql的php版
Jun 30 PHP
php防止网站被攻击的应急代码
Oct 21 PHP
一波PHP中cURL库的常见用法代码示例
May 06 PHP
PHP实现的登录,注册及密码修改功能分析
Nov 25 PHP
Thinkphp5结合layer弹窗定制操作结果页面
Jul 07 PHP
如何修改Laravel中url()函数生成URL的根地址
Aug 11 PHP
php curl获取https页面内容,不直接输出返回结果的设置方法
Jan 15 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下使用strpos需要注意 === 运算符
2010/07/17 PHP
2款PHP无限级分类实例代码
2015/11/11 PHP
PHP网页缓存技术优点及代码实例
2020/07/29 PHP
快速保存网页中所有图片的方法
2006/06/23 Javascript
代码精简的可以实现元素圆角的js函数
2007/07/21 Javascript
javascript实现上传图片并预览的效果实现代码
2011/04/11 Javascript
JQuery制作的放大效果的popup对话框(未添加任何jquery plugin)分享
2013/04/28 Javascript
toggle一个div显示或隐藏且可扩展成自定义下拉框
2013/09/12 Javascript
基于jquery的simpleValidate简易验证插件
2014/01/31 Javascript
JS中的Replace方法使用经验分享
2015/05/20 Javascript
通过node-mysql搭建Windows+Node.js+MySQL环境的教程
2016/03/01 Javascript
EasyUI Pagination 分页的两种做法小结
2016/07/09 Javascript
AngularJs上传前预览图片的实例代码
2017/01/20 Javascript
小程序开发踩坑:页面窗口定位(相对于浏览器定位)(推荐)
2019/04/25 Javascript
JS常见面试试题总结【去重、遍历、闭包、继承等】
2019/08/27 Javascript
react 生命周期实例分析
2020/05/18 Javascript
vue 使用vant插件做tabs切换和无限加载功能的实现
2020/11/04 Javascript
vue $router和$route的区别详解
2020/12/02 Vue.js
[10:49]2014国际邀请赛 叨叨刀塔第二期为真正的电竞喝彩
2014/07/21 DOTA
[54:41]2018DOTA2亚洲邀请赛3月30日 小组赛B组 VGJ.T VS paiN
2018/03/31 DOTA
在Python中处理列表之reverse()方法的使用教程
2015/05/21 Python
windows 下python+numpy安装实用教程
2017/12/23 Python
详解pyenv下使用python matplotlib模块的问题解决
2018/11/29 Python
浅谈pycharm的xmx和xms设置方法
2018/12/03 Python
python装饰器常见使用方法分析
2019/06/26 Python
Django的CVB实例详解
2020/02/10 Python
Python3 中sorted() 函数的用法
2020/03/24 Python
python实现批量转换图片为黑白
2020/06/16 Python
详解用python -m http.server搭一个简易的本地局域网
2020/09/24 Python
python 递归相关知识总结
2021/03/03 Python
Foot Locker加拿大官网:美国知名运动产品零售商
2019/07/21 全球购物
小学班长竞选演讲稿
2014/04/24 职场文书
企业家王石演讲稿:坚持与放下
2014/04/27 职场文书
小学生运动会报道稿
2014/09/12 职场文书
党员教师个人对照检查材料范文
2014/09/25 职场文书
事业单位聘任报告
2015/03/02 职场文书