tp5底层源码分析之------tp5.1类的自动加载机制
tp框架作为国内主流框架,目前已经发布了6.0版本,相当于3.*版本是进行了重构,今天我们从源码的角度来研究下tp5.1自动加载的实现
作为单入口框架,从入口文件看起,入口文件在public/下,那么为什么大多数框架要把入口文件放到子文件夹下面呢?
第一,为了动静分离,因为现在的tp框架一般都是单入口,既然是单入口,那么必然要做rewrite,如果把静态文件和程序文件放到一起。
框架路由势必要对每一个请求进行筛选,所以这些框架不约而同的把资源文件和程序文件区分开来,放在了不同的文件夹下面,所以从整体
来看,也就是为什么入口会在子目录了。
第二,为了安全,linux下的权限划分非常严格,分贝氛围读,写,执行。在这个基础上又分为文件所有组,所在组,其他组。这样划分可以
更好的对文件权限进行梳理,避免上传漏洞(用户上传php文件被执行)等等。
1.我们来看下入口文件:


2. tp5.1入口文件引入加载了base.php文件,然后base.php文件中载入了loader.php类,并且执行了Loader::register()静态方法,我们来看看register方法内部执行了

2.1)在第79行也就是register()方法中执行了内置函数apl_autoloader_register(),此函数的第一个参数接收一个匿名函数,或者回调方法,作用是每当php
调用了不存在的类时就会执行此函数当中的回调函数,且携带一个参数,值是引入的未存在的带命名空间的类名(如果有类名空间),如在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中, 在商法的类中存在两个静态成员属性:$prefixLengthsPsr4、$prefixDirsPsr4。形式如下图:

这两个成员属性是根据psr-4规范规则 而生成,不懂的可自己百度了解。这里将成员属性复制到本类后,后面加载文件时查找类的文件路径会用到,下面再讲。
3)我们来看下注册命名空间定义:注册think和tratis两个两个文件夹路径,调用self::addNamespace方法,主要做的事情就是将这两个命名空间、文件路径以psr-4规范形式 加入到上面所提的两个成员属性中$prefixLengthsPsr4、$prefixDirsPsr4。$prefixLengthsPsr4规则:将命名空间首字母当做第一维数组的键,将命名空间当做第二维数组的键,将此命名空间字符串长度当做第二维数组的值。$prefixDirsPsr4规则:将命名空间当做第一维数组的键,将对应的文件绝对路径当做第二维数组的值,第二位数组的键是自增的索引值。此时本类中的静态成员属性$prefixLengthsPsr4、$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异曲同工
tp5底层源码分析之------tp5.1类的自动加载机制的更多相关文章
- 精尽 MyBatis 源码分析 - MyBatis 初始化(一)之加载 mybatis-config.xml
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - MyBatis初始化(二)之加载Mapper接口与XML映射文件
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- Log4j2源码分析系列:(一)配置加载
前言 在实际开发项目中,日志永远是一个绕不开的话题.本系列文章试图以slf4j和log4j2日志体系为例,从源码角度分析日志工作原理. 学习日志框架,首先要熟悉各类日志框架,这里推荐两篇文章,就不再赘 ...
- List-LinkedList、set集合基础增强底层源码分析
List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...
- List-ArrayList集合基础增强底层源码分析
List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...
- LInkedList总结及部分底层源码分析
LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...
- Vector总结及部分底层源码分析
Vector总结及部分底层源码分析 1. Vector继承的抽象类和实现的接口 Vector类实现的接口 List接口:里面定义了List集合的基本接口,Vector进行了实现 RandomAcces ...
- thinkphp5源码剖析系列1-类的自动加载机制
前言 tp5想必大家都不陌生,但是大部分人都停留在应用的层面,我将开启系列随笔,深入剖析tp5源码,以供大家顺利进阶.本章将从类的自动加载讲起,自动加载是tp框架的灵魂所在,也是成熟php框架的必备功 ...
- JAVA ArrayList集合底层源码分析
目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...
随机推荐
- APP自動化測試腳本2
package com.lemon.day01; import java.net.MalformedURLException; import java.net.URL; import java.uti ...
- 多智能体系统(MAS)简介
1.背景 自然界中大量个体聚集时往往能够形成协调.有序,甚至令人感到震撼的运动场景,比如天空中集体翱翔的庞大的鸟群.海洋中成群游动的鱼群,陆地上合作捕猎的狼群.这些群体现象所表现出的分布.协调.自 ...
- gym102346题解
B Buffoon 判断最大值是不是第一个数,签到题. H Hour for a Run 输出\(n*m\)的\(10\%\)到\(90\%\),签到题,注意别用浮点数和ceil,有精度问题. M M ...
- 要不要学习Git(分布式版本控制系统)
做技术的人,要不要学一学Git呢? 提出这个问题,是因为很多小伙伴还不会使用Git. 对于任何新一代的技术工具,它在业界普及都有一个过程,Git的阻碍是:学习成本.工具迭代的成本. SVN诞生于200 ...
- 基于C#的机器学习--c# .NET中直观的深度学习
在本章中,将会学到: l 如何使用Kelp.Net来执行自己的测试 l 如何编写测试 l 如何对函数进行基准测试 Kelp.Net是一个用c#编写的深度学习库.由于能够将函数链到函数堆栈中,它在 ...
- Flask基础(02)-->搭建Flask项目虚拟环境
什么是虚拟环境? 虚拟环境:其实就是一个文件夹,是python环境的复制 为什么要搭建虚拟环境? 因为一台计算机上可能要同时开发多个不同的项目,那么这些项目有可能用到同一个包的不同版本,如此一来,我们 ...
- 深入了解String,StringBuffer和StringBuilder三个类的异同
Java提供了三个类,用于处理字符串,分别是String.StringBuffer和StringBuilder.其中StringBuilder是jdk1.5才引入的. 这三个类有什么区别呢?他们的使用 ...
- C++——数组与字符串
目录 一.数组 1.1定义与初始化 1.1.1使用 1.1.2存储 1.1.3初始化 1.2作函数参数 1.3对象数组 1.3.1定义与访问 1.3.2初始化 1.3.3数组元素所属类的构造函数 二. ...
- Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- android 6.0导航栏 NavigationBar影响视图解决办法
在开发app的时候会遇到有些测试手机没有物理按钮,比如最近在做的一个app在小米手机上运行显示效果很好,但是在华为P7手机上显示就乱了,底部的NavigationBar直接覆盖在主视图上,导致按钮无法 ...