0

0

php面试题四之实现autoload

不言

不言

发布时间:2018-04-18 09:40:56

|

3525人浏览过

|

来源于php中文网

原创

这篇文章介绍的内容是关于php面试题四之实现autoload,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

yii框架宣称自己的类加载方式很高效,是真正的“用时加载”,那究竟特别在哪里?今天研究了一下源码,发现其实是在代码级加了一层“路径缓存”

Yii2 的自动加载原理

我们知道,要实现自己的autoload方法,需要采用spl_autoload_register()函数注册一个autoload方法,Yii注册的这个方法是YiiBase::autoload(),稍后再讲解这个方法的逻辑。另外,Yii一般都用Yii::import($pathAlias, $forceInclude=false)来加载相应的类(这个方法直接调用了YiiBase::import() ),这个方法配合YiiBase::autoload()就能实现“用时加载”了。

先说import的大致逻辑:
1、检查self::$_imports数组是否存在相应的$pathAlias,如果有说明已经加载过了,直接返回类名或者目录名;否则继续第2步;
2、根据路径别名获得实际的路径名,并根据路径别名最后一部分是否是“*”可以知道要加载的路径别名是否是一个文件,如果是文件,去第3步;否则去第4步;
3、如果是$forceInclude是true,则立即require这个文件,并在$_imports数组中增加一项$alias => $className;否则在数组$classMap中缓存一项$className => $realPath
4、对于路径,会在数组$_includePaths中缓存这个路径,并且在$_imports数组中增加一项$alias => $realPath
5、结束。
因为$forceInclude默认都为false,所以import不会立即加载相应的类,等到使用时才真正加载,这是YiiBase::autoload的工作。

autoload的大致逻辑:
1、检查类名是否已缓存在$classMap$_coreClasses数组中,如果是则直接require相应的文件路径,$_coreClasses是框架自有类的映射表;否则去第2步;
2、检测YiiBase::$enableIncludePath是否为false,如果是则去第3步,否则直接include($className . '.php')
3、遍历$includePaths数组,将目录名拼接上类名,检查是否为合法的php文件,如果是则include,然后跳出循环
4、结束。
需要注意的是,文档指出:如果要与其他类库一起使用,必须将$enableIncludePath置为false,以便在Yii::autoload()失败时,其他类库的autoload方法有机会执行。
//$enableIncludePath 是否要依靠PHP包含路径到自动加载类文件。默认为true. 如果你的宿主环境不允许你改变PHP包含路径,可以设置为false, 或者你想添加另外的自动加载器到默认的Yii 自动加载器.

官方描述文档

在Yii中,所有类、接口、Traits都可以使用类的自动加载机制实现在调用前自动加载。Yii借助了PHP的类自动加载机制高效实现了类的定位、导入,这一机制兼容 PSR-4 的标准。在Yii中,类仅在调用时才会被加载,特别是核心类,其定位非常快,这也是Yii高效高性能的一个重要体现。

立即学习PHP免费学习笔记(深入)”;

自动加载机制的实现
Yii的类自动加载,依赖于PHP的 spl_autoload_register() , 注册一个自己的自动加载函数(autoloader),并插入到自动加载函数栈的最前面,确保Yii的autoloader会被最先调用。

类自动加载的这个机制的引入要从入口文件 index.php 开始说起:

run();

这个文件主要看点在于第三方autoloader与Yii 实现的autoloader的顺序。不管第三方的代码是如何使用 spl_autoload_register() 来注册自己的autoloader的,只要Yii 的代码在最后面,就可以确保其可以将自己的autoloader插入到整个autoloder 栈的最前面,从而在需要时最先被调用。

接下来,看看Yii是如何调用 spl_autoload_register() 注册autoloader的, 这要看 Yii.php 里发生了些什么:

这段代码,调用了 spl_autoload_register(['Yii', 'autoload', true, true]) ,将 Yii::autoload() 作为autoloader插入到栈的最前面了。并将 classes.php 读取到 Yii::$classMap 中,保存了一个映射表。

在上面的代码中,Yii类是里面没有任何代码,并未对 BaseYii::autoload() 进行重载,所以,这个 spl_autoload_register() 实际上将 BaseYii::autoload() 注册为autoloader。如果,你要实现自己的autoloader,可以在 Yii 类的代码中,对 autoload() 进行重载。

在调用 spl_autoload_register() 进行autoloader注册之后,Yii将 calsses.php 这个文件作为一个映射表保存到 Yii::$classMap 当中。这个映射表,保存了一系列的类名与其所在PHP文件的映射关系,比如:

return [  'yii\base\Action' => YII2_PATH . '/base/Action.php',  'yii\base\ActionEvent' => YII2_PATH . '/base/ActionEvent.php',  ... ...

  'yii\widgets\PjaxAsset' => YII2_PATH . '/widgets/PjaxAsset.php',  'yii\widgets\Spaceless' => YII2_PATH . '/widgets/Spaceless.php',
];

这个映射表以类名为键,以实际类文件为值,Yii所有的核心类都已经写入到这个 classes.php 文件中,所以,核心类的加载是最便捷,最快的。现在,来看看这个关键先生 BaseYii::autoload()

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[$className] 看看是否在映射表中已经有拟加载类的位置信息;

百度智能云·曦灵
百度智能云·曦灵

百度旗下的AI数字人平台

下载

如果有,再看看这个位置信息是不是一个路径别名,即是不是以 @ 打头, 是的话,将路径别名解析成实际路径。 如果映射表中的位置信息并非一个路径别名,那么将这个路径作为类文件的所在位置。 类文件的完整路径保存在 $classFile ;

如果 $classMap[$className] 没有该类的信息, 那么,看看这个类名中是否含有 \ , 如果没有,说明这是一个不符合规范要求的类名,autoloader直接返回。 PHP会尝试使用其他已经注册的autoloader进行加载。 如果有 \ ,认为这个类名符合规范,将其转换成路径形式。 即所有的 \ 用 / 替换,并加上 .php 的后缀。

将替换后的类名,加上 @ 前缀,作为一个路径别名,进行解析。 从别名的解析过程我们知道,如果根别名不存在,将会抛出异常。 所以,类的命名,必须以有效的根别名打头:

// 有效的类名,因为@yii是一个已经预定义好的别名use yii\base\Application;// 无效的类名,因为没有 @foo 或 @foo/bar 的根别名,要提前定义好use foo\bar\SomeClass;

使用PHP的 include() 将类文件加载进来,实现类的加载。

从其运作原理看,最快找到类的方式是使用映射表。 其次,Yii中所有的类名,除了符合规范外,还需要提前注册有效的根别名。

运用自动加载机制
在入口脚本中,除了Yii自己的autoloader,还有一个第三方的autoloader:

require(__DIR__ . '/../../vendor/autoload.php');

这个其实是Composer提供的autoloader。Yii使用Composer来作为包依赖管理器,因此,建议保留Composer的autoloader,尽管Yii的autoloader也能自动加载使用Composer安装的第三方库、扩展等,而且更为高效。但考虑到毕竟是人家安装的,人家还有一套自己专门的规则,从维护性、兼容性、扩展性来考虑,建议保留Composer的autoloader。

如果还有其他的autoloader,一定要在Yii的autoloader注册之前完成注册,以保证Yii的autoloader总是最先被调用。

如果你有自己的autoloader,也可以不安装Yii的autoloaer,只是这样未必能有Yii的高效,且还需要遵循一套类似的类命名和加载的规则。就个人的经验而言,Yii的autoloader完全够用,没必要自己重复造轮子。

相关推荐:

php面试题三之yii2和yii的不一样的地方

php面试题二之用到过的传输协议

php面试题一之线程和进程的区别(顺带提下协程)

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2520

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1599

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1493

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

952

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1416

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1234

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1445

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1306

2023.11.13

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.6万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 7万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号