tp5底层源码分析之------tp5.1类的自动加载机制

tp框架做为国内主流框架,目前已经发布了6.0版本,至关于3.*版本是进行了重构,今天咱们从源码的角度来研究下tp5.1自动加载的实现php

    做为单入口框架,从入口文件看起,入口文件在public/下,那么为何大多数框架要把入口文件放到子文件夹下面呢?linux

 第一,为了动静分离,由于如今的tp框架通常都是单入口,既然是单入口,那么必然要作rewrite,若是把静态文件和程序文件放到一块儿。数组

框架路由势必要对每个请求进行筛选,因此这些框架不约而同的把资源文件和程序文件区分开来,放在了不一样的文件夹下面,因此从总体安全

来看,也就是为何入口会在子目录了。composer

   第二,为了安全,linux下的权限划分很是严格,分贝氛围读,写,执行。在这个基础上又分为文件全部组,所在组,其余组。这样划分能够框架

更好的对文件权限进行梳理,避免上传漏洞(用户上传php文件被执行)等等。函数

    1.咱们来看下入口文件:spa

 

    2. tp5.1入口文件引入加载了base.php文件,而后base.php文件中载入了loader.php类,而且执行了Loader::register()静态方法,咱们来看看register方法内部执行了什么?命令行

 2.1)在第79行也就是register()方法中执行了内置函数apl_autoloader_register(),此函数的第一个参数接收一个匿名函数,或者回调方法,做用是每当php3d

调用了不存在的类时就会执行此函数当中的回调函数,且携带一个参数,值是引入的未存在的带命名空间的类名(若是有类名空间),如在base.php20行注册异常机制,那么这是携带的参数值是:think\Error.

  

 2.2)继续往下看,Loader类中的80跟81行,分别是得到本项目的绝对路径以及得到vender目录下composer文件夹的绝对路径,咱们打印输出看下

2.3)85行后面,判断是否存在composer文件夹,是否存在autoload_static.php 文件,由于5.1版本后,php官网再也不提供下载版本,只支持经过composer下载,因此这个文件必定是存在的。而后加载了这个类文件。

2.4)89行执行了 get_declared_classes() 函数,此函数功能是获取由当前脚本中已定义类的名字组成的数组(包括本身引入的类,和php内置的一些类)。而后90行取出此数组中最后一个元素,也就是刚刚引入的autoload_static.php中的类,返回值是:Composer\Autoload\ComposerStaticInit3ec0ccb9b30037c3270e4e4566239878

2.5)91行,循环将刚才得到到的类中 成员属性 复制到本类Loader中, 在商法的类中存在两个静态成员属性:$prefixLengthsPsr四、$prefixDirsPsr4。形式以下图:

 这两个成员属性是根据psr-4规范规则 而生成,不懂的可本身百度了解。这里将成员属性复制到本类后,后面加载文件时查找类的文件路径会用到,下面再讲。

3)咱们来看下注册命名空间定义:注册think和tratis两个两个文件夹路径,调用self::addNamespace方法,主要作的事情就是将这两个命名空间、文件路径以psr-4规范形式 加入到上面所提的两个成员属性中$prefixLengthsPsr四、$prefixDirsPsr4。$prefixLengthsPsr4规则:将命名空间首字母当作第一维数组的键,将命名空间当作第二维数组的键,将此命名空间字符串长度当作第二维数组的值。$prefixDirsPsr4规则:将命名空间当作第一维数组的键,将对应的文件绝对路径当作第二维数组的值,第二位数组的键是自增的索引值。此时本类中的静态成员属性$prefixLengthsPsr四、$prefixDirsPsr4的值以下图:

 4).106行加载类库映射文件,

它会查找项目根目录下\runtime\classmap.php文件,将此文件中的一维数组值赋值到本类成员属性$classMap。这个文件是经过执行tp5.1命令行命令:php think optimize:autoload 生成的。生成的文件中包含了全部将要引入的类的 类名与文件绝对路径 的映射,此文件会提升寻找类文件的效率,通常项目完成时生成,若是后续有新建的类的话,此文件须要从新生成才能寻找到新的类文件。后面会讲到为什么会提升加载类的效率。默认是没有此文件的。

5)此方法的最后一行118行,自动加载extend目录,调用self::addAutoLoadDir()方法,作的事情是:将项目根目录下的extend目录绝对路径放到 成员属性 $fallbackDirsPsr4中。

6)Loader::autoload自动加载时执行的方法

  上面说到 spl_autoload_register()函数,若是调用不存在的类时将执行此函数中的第一个参数方法。那么将调用本类中的autoload方法。此方法代码:

上面说了,此方法的参数$class的值的带有命名空间的类名,127行判断本类中的成员属性$classAlias中是否存在此类名,若是存在,则将此类名设置别名,开始此属性值是空数组。继续往下,调用了self::findFile方法并将类名当作参数传入,返回$file值,下方140行引入此文件。咱们来看看findFile方法作了哪些事情:

 6.1)143行,首先判断成员属性$classmap中是否存在此类名的键,若是存在则直接返回。咱们上方说到此成员属性值是执行tp5.1命令行命令生成的,因此生成文件后就再也不往下执行 循环判断文件是否存在,直接返回文件路径,因此能够提升文件查找效率。

6.2)

if中执行的逻辑是根据psr-4规范查找类文件,具体是这样:取出这个带有命名空间类的第一个字母,判断成员属性$prefixLengthsPsr4是否存在此首字母的键值,而后循环这个键值,判断命名空间有没有是否存在$prefixLengthsPsr4二维的键,若是存在,根据$prefixDirsPsr4属性取出命名空间对应的绝对路径,而后拼接文件名,判断文件是否存在,若是存在则返回文件的绝对路径。

6.3)

 循环$fallbackDirsPsr4属性下全部值拼接文件名,返回绝对路径并判断文件是否存在,若存在则返回。

6.4):

 

 根据psr-0规则判断文件是否存在并返回,跟上方的psr-4殊途同归

相关文章
相关标签/搜索