起始准备
安装
composer config -g repo.packagist composer https://packagist.phpcomposer.com
composer create-project topthink/think:5.1.20
先来到public/index.php
文件
自动加载文件路径thinkphp/library/think/Loader.php
可以先引入了,thinkphp/base.php
文件,刚进去查看
此文件引入了thinkphp/library/think/Loader.php
,并且调用了自动加载函数,然后就可以分析自动加载类了
自动加载
register
静态函数
进入自动加载文件后,找到register
静态方法进行分析(一个功能一个功能的分析)
这里使用了spl_autoload_register
这个函数,这个函数就是用来自动加载的,当我们访问一个不存在的类的时候,就会调用这个函数spl_autoload_register
参数介绍
- 第一个参数写的是函数名,当访问不存在的类时,
spl_autoload_register
就会调用这个参数 - 第二个参数就是第一个参数指定的函数无法成功注册时, spl_autoload_register()是否抛出异常。
- 第三个参数把此函数放到队列的首位,说人话就是,让他优先执行
所以这里的spl_autoload_register
函数就是在访问到不存在的类是会调用think\\Loader::autoload
这个方法或者是我们指定的方法,因为他第一个参数是个三元运算符,在我们没有指定的自动加载的方法时会使用默认的方法。
剩下的一行是用来获取当前项目的路径,就是你tp
项目的路径
第一行是用来获取Composer
的路径的
然后判断是否有thinkphp/vendor/composer/
目录,然后没有的话这个功能点就结束了
然后继续判断是否存在autoload_staic.php
文件,如果不存在,就会调用registerComposerLoader
,此方法会判断存在哪些文件,然后加载对应的文件,如果是空目录的话此功能点结束(具体可以进去此函数分析)
然后回去包含autoload_static.php
此文件,进去瞅瞅
这里有2个静态成员很重要$prefixLengthsPsr4
和$prefixDirsPsr4
后面分析有用,继续回到Loader.php
包含autoload_static.php
此文件后,他会执行get_declared_classes
函数,用来获取当前所有的类(包括自定义的)返回值是数组,从$declaredClass
这个数组里面弹出最后一个元素并且赋值给$composerClass
(最后一个元素就是刚刚包含的autoload_staic.php
这个类)
输出的就是autoload_static.php
文件里面的类,然后他会用一个foreach
循环数组,然后用property_exists
函数来判断该类是否有该成员,如果有的话就创建一个静态成员,并且值是该类成员的值,刚刚看到的autoload_staic.php
这个文件只存在数组的前面2个成员,我们可以输出看一下,创建静态变量的值
所以他就是那2个类成员的值。
下一个功能
这里调用了一个静态函数addNamespace
此函数用来注册命名空间,传递了1个数组,进去此函数查看
这里判断他是不是数组,是数组的话就用foreach
循环里面的内容,不是数组就直接调用了,因为刚刚都说了传递的参数是数组,然后他就会执行foreach
循环,把数组的key
变成$perfix
,value
变成$paths
然后把$prefix
和/
字符进行拼接,又调用了一个静态函数addPsr4
,在进去查看addPsr4
函数
这里调用的是一个if
语句,一般的流程是会进入第二个elseif
这里,使用我分析的也是这里,他会先判断,我们的静态成员$prefixDirsPsr4
是否存在传入的$prefix
(这里拿think\
那条数据举例)。$prefixDirsPsr4
不存在think\
返回False
因为前面有个!
所以返回True
,继续执行。
然后计算$prefix
的长度
在判断$prefix
的最后一个字符是否是\
,是的话向下执行,不是的话抛出异常
然后把think\
的长度加入到$prefixLengthsPsr4
数组中,加入过程,
例如think\\
就变成这样$prefixLengthsPsr4['t']['think\\']=$length
然后在把$paths
加入到$prefixDirsPsr4
数组中。
加入完成后此功能也执行完毕,我们看看最后$prefixLengthsPsr4
和$prefixDirsPsr4
这2个数组的值
下一个功能
这里他判断是否有runtime/classmap.php
这个文件,有的话就包含,没有的话此功能结束,默认是没有的,不过我们可以用php think optimize:autoload
生成
然后看看runtime/classmap.php
这个文件
这里面其实就是一个数组,用来映射类,回到Loader.php
此功能会包含此文件,然后在传入addClassMap
静态函数,进去此函数查看作用
看到他把2个数组合并然后放到静态变量$classMap
中
最后一个功能
调运了个静态函数addAutoLoadDir
,把extend
路径传入,此函数代码就一条
// 注册自动加载类库目录
public static function addAutoLoadDir($path)
{
self::$fallbackDirsPsr4[] = $path;
}
很简单,把$path
加入到$fallbackDirsPsr4
静态数组中
这就是register
函数的功能
autoload
静态函数
此函数代码
public static function autoload($class)
{
if (isset(self::$classAlias[$class])) {
return class_alias(self::$classAlias[$class], $class);
}
if ($file = self::findFile($class)) {
// Win环境严格区分大小写
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
__include_file($file);
return true;
}
}
先会判断$class
是否是类的别名,如果是类的别名就返回true
继续执行,类的别名在base.php
有定义。
然后调用,findFile
来寻找对应的类的文件,进入findFile
类
此方法也一个功能点一个功能点的分析
if (!empty(self::$classMap[$class])) {
// 类库映射
return self::$classMap[$class];
}
这里就是看看$classMap
是否有映射,如果有映射的话直接访问,所以生成的runtime/classmap.php
可以提升点性能。
// 查找 PSR-4
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
$first = $class[0];
if (isset(self::$prefixLengthsPsr4[$first])) {
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
此功能首先进行替换,然后拼接'.php'
获取第一个$class
的第一个字母
判断prefixLengthsPsr4
是否有这个元素首字母对应的值,没有退出执行下一个功能
然后循环获取对应的key
和value
然后判断我们的$class
的字符串首次在$prefix
的字符串首次出现的位置,这里基本上都是返回0,也就是会往下执行
然后在$prefixDirsPsr4
寻找对应的目录,判断是否存在此目录,然后返回此文件名
下一个功能
// 查找 PSR-4 fallback dirs
foreach (self::$fallbackDirsPsr4 as $dir) {
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
这里的$fallback
就是extend
那个目录的路径,这里直接进行拼接,然后判断是否有该文件,例如我传入的类是test
类,那么拼接的路径就是thinkphp\extend\test.php
(返回的是绝对路径,我这里用的是相对路径)
其他功能可以自己去查看源码
本站文章除注明转载/出处外,均为本站原创或翻译,如若转载,请注明出处。