page contents

php 自动加载原理

说起PHP的自动加载,我们可能马上想到的是各种框架的自动加载功能,PHP规范中的PSR0和PSR4原则, Composer 的自动加载功能等等。

attachments-2020-08-DdDv3rB85f46205019069.png

1. 自动加载与 Psr0、Psr4 和 Composer 的关系?

说起PHP的自动加载,我们可能马上想到的是各种框架的自动加载功能,PHP规范中的PSR0和PSR4原则, Composer 的自动加载功能等等。PSR0和PSR4原则只是为我们定义自动加载的类提供了统一的规范,例如:命名空间,而 Composer 同样是利用了这个统一规范加入了自动加载构成一个完整的组件包,为我们的开发提供了很大的方便。


2. 为什么会有自动加载

在PHP面向对象(OO)编程中,为了方便管理,我们都会把一个类写在一个单独的文件中,那么如果想在A类中使用B类的功能,就需要把B类加载到A类。对于这样的需求在最原始的时候,我们是通过require 和 include 语法实现的。
PHP5实现了类的自动加载(Autoload)功能,减少传统方式的文件引入方式带来的复杂性,如:文件嵌套依赖、方法名冲突等。


3. __autoload()自动加载

PHP5实现了类的自动加载(Autoload)功能,这个功能最初是通过PHP的一个魔术方法__autoload()实现的。后来,PHP扩展SPL(Standard PHP Library 标准PHP类库)又实现了更强大的自动加载机制。

我们需要明确__autoload()函数PHP在找不到类的时候会自动执行,但是PHP内部并没有定义这个函数,这个函数需要开发着自己定义,并且编写内部逻辑,PHP只负责在需要的时候自动调用执行。而且在调用的时候会自动传人要加载的类名作为参数。


4. __autoload()自动加载与SPL自动加载的关系

有了__autoload()函数,可以看出,如果我们现在需要引入100个其它文件,只需要订好一个规则,编写一个函数就可以了。这比直接用require/inlude有了很大进步,但是同样也有新的问题,在一个项目中,我们只能编写一个__autoload()函数,如果项目比较大,加载每个文件都使用同样的规则显然是不现实的,那么我们可能就需要在__autoload()中编写复杂的规则逻辑来满足加载不同文件的需求。这同样会使得__autoload()函数变得复杂臃肿,难以维护管理。
于是,SPL(Standard PHP Library 标准PHP类库)的自动加载机制就应时而生了。


5. SPL自动加载原理

首先,明确一点,PHP在实例化一个对象时(实际上在实现接口,使用类常数或类中的静态变量,调用类中的静态方法时都会如此),首先会在系统中查找该类(或接口)是否存在,如果不存在的话就尝试使用autoload机制来加载该类。而autoload机制的主要执行过程为:

1、检查执行器全局变量函数指针autoload_func是否是NULL;

2、如果 autoload_func==NULL ,则查找系统是否定义 **__autoload() **函数,如果定义了,则执行并返回加载结果。如果没有定义,则报错并退出;

3、如果 autoload_func 不等于NULL,则直接执行 autoload_func 指向的函数加载类,此时并不检查 __autoload() 函数是否定义。


通过对PHP自动加载流程的了解,可以看到PHP实际上提供了两种方法来实现自动装载机制:

a. 一种我们前面已经提到过,是使用用户定义的__autoload()函数,这通常在PHP源程序中来实现;

b. 另外一种就是设计一个函数,将autoload_func指针指向它,这通常使用C语言在PHP扩展中实现,即 SPL autoload机制。

如果两种方式都实现了,也就是 autoload_func 不等于NULL,程序只会执行第二种方式,__autoload() 函数是不会被执行的。


详细分析SPL自动加载过程

假如把spl_autoload_register(’my_autoload’) 改成 spl_autoload_register()不添加任何参数,B类能被加载吗?答案是:YES。


为什么呢?

因为SPL扩展内部自己定义了一个自动加载函数 spl_autoload(),实现了自动加载的功能,如果我们不定义自己的自动加载函数,并且程序里写了 spl_autoload_register()(如果不传参数,必须是第一次执行才会有效)或者 spl_autoload_register(’spl_autoload’),那么autoload_func 指针就会指向内部函数 spl_autoload()。程序执行的时候如果找不到相应类就会执行该自动加载函数。


那么,SPL 是怎么实现autoload_func 指针指向不同的函数呢?

原来,在SPL内部定义了 一个函数 spl_autoload_call() 和 一个全局变量autoload_functions。autoload_functions本质上是一个HashTable,不过我们可以将其简单的看作一个链表,链表中的每一个元素都是一个函数指针,指向一个具有自动加载类功能的函数。

spl_autoload_call()的作用就是按顺序遍历 autoload_functions,使得autoload_func指向每个自动加载函数,如果加载成功就停止,如果不成功就继续遍历下个自动加载函数,直到加载成功或者遍历完所有的函数。

那么,autoload_functions 这个列表是谁来维护的呢?就是 spl_autoload_register() 这个函数。我们说的自动加载函数的注册,其实就是通过spl_autoload_register()把自动加载函数加入到 autoload_functions 列表。


attachments-2020-08-zTu2lGwF5f4620c80588e.jpg

  • 发表于 2020-08-26 16:44
  • 阅读 ( 689 )
  • 分类:操作系统

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1474 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章