之前写过一篇文章是关于composer 的基本用法,这篇文章是composer源码的简单阅读和thinkphp5.1的自动加载。
先来熟悉一个函数,get_declared_classes, 这个函数是干嘛的?是获取当前脚本中已经加载的类的,但凡这个返回结果中有的类,我们都可以直接生成,默认在一个空脚本中
1 | <?php |
是当前php中包含的所有扩展类,那如果没有包含在这其中的类我们应该怎么生成实例对象呢?远古时代是通过 require_once,想想添加每个新脚本的时候都要在上面写个require, 这样太不智能了,php给我们提供了一个函数spl_autoload_register, 通过不断的调用这个函数,可以绑定自定义的函数到一个队列中,如果我们生的对象的类在内存中找不到,他就会执行这个队列中的所有自定义方法,直到找到为止, composer 本质上也是基于这个函数。
1 | 来自composer ClassLoader.php |
当我们在github上安装一个包(或者叫库), 我们先composer require, 安装完了之后再在我们的脚本中加上 vendor/autoload.php, 然后就能用了,注意一定要require_once vendor/autoload.php 这个文件,否则你只是下载了包,当生成对象的时候,内存中还是没有这个类的存在(以klein举例)
那我们开看一下这个autoload .php
1 | <?php |
调用的是composer 包中autoload_real 中的getLoader 方法
1 | public static function getLoader() |
好了,我们来总结一下composer 文件夹中的几个比较重要的文件,autoload_real.php 是注册Classload .php 成为spl_autoload_register中的方法,autoload_static.php类似一个配置文件,把他包含的类对应文件夹的属性都绑定到ClassLoad 上,ClassLoad 调用自己的loadClass 方法,根据类名,去自己的属性上找对应的类所在文件位置。
现在抛出问题,我们如何不通过composer require去安装一个库文件?
其实很简单,composer require 做了两个工作,首先git clone 那个库到你本地vendor目录,再接着配置autoload_static.php 文件中的两个属性,prefixLengthsPsr4, prefixDirsPsr4,第一个属性是命名空间的首字母对应命名空间,第二个是命名空间对应类的文件位置,配置好了之后,我们就可以试着new class了,看会不会报错,一般情况下不会,除非这个类库中除了psr4 还有classMap 或者files 或者psr0,这样我们一点点的添加,就能完成。
接着我们看看thinkphp5.1 的自动加载机制,thinkphp的自动加载其实就是composer的翻版,他为了兼容composer, composer 中的文件没有动,只是他没有require vendor 下面的autoload.php, 转而是通过think 库 base.php ->load.php,这个load.php 作用类似composer 的autoload_real 和 CLassLoader,
load.php 中的register 方法通过获取composer 的autload_static 中的prefixLengthsPsr4’, ‘prefixDirsPsr4 属性,绑定到自身,获取了composer 中通过psr4 加载的类,顺便把自己的think 和 trait也加入其中.
对于classMap, 他获取的自己runtime 文件夹下的classMap.php 文件中的内容,该内容需要调用命令生成,就是thinkphp 自身的类和对应文件位置的集合。
最后是自动加载目录,他的功能类似psr4,就是把自动加载的目录当做根目录,类文件按照psr4,由这个相对根目录展开。
thinkphp 还有个classAlias 功能,classAlias 利用的是class_alias 这个方法,让两个类一模一样,除了类名,这样可以简写我们的类名长度,注意使用的时候一定要加上根命名空间\,否则可能会在当前命名空间下寻找改类,这个在laravel中用的也很多
1 | // 注册类库别名 |
好了,大致就这么多了,所以我们可以猜测一波(没有仔细看啦)
composer dump-autoload,主要是因为我们修改了composer.json文件中的autoload.psr4选项,没有及时修改autload_static 文件,
composer require 1. git clone 2.修改autoload_static 文件
实战:如何用命令行的方式运行tp,测试tp中的函数
首先因为tp重写了composer 的加载方式(但没有修改composer 的文件, 为了方便composer update, install ), 所以我们用不了vendor 中的_autoload.php, tp起到相同作用的是 Loader::register 方法,这个方法中 对app 文件夹,和 think\composer 进行了psr4 加载,同时把thinkphp 核心文件夹library 下的think 和traits 也进行psr4 进行加载,这样我们就能访问app , think\composer, thinkphp\libraray\think和thinkphp\libraray\traits 下的所有文件了。同时他还通过loader 的addAutoLoadDir 把extend 文件夹做成classmap 进行加载,所以为了测试我建立了cy文件夹,也需要Load::addAutoLoadDir(realpath(‘cy’))。 当然如果我们还可能为了方便使用系统的一些类,需要class_alias。
1 | <?php |
其实为什么要遵循ps4规范,就是为了能够通过命名空间方便查找文件的具体位置,然后require, 当我们主动require 了文件(比如文件数量过少的情况),我们的命名空间可以随便定义的,并没有任何硬性规定一定要和文件夹名称相同,你甚至可以在一个根目录下定义一长串的命名空间前缀,没有任何语法错误的。