PHP自动加载机制

本文详细介绍了PHP的自动加载机制,包括__autoload和SPL autoload的工作原理。通过示例,阐述了如何使用和注册自动加载函数,以及如何解决效率问题。文中提到,合理的类名与文件映射规则对于提高自动加载效率至关重要。
摘要由CSDN通过智能技术生成

自动加载机制的主要执行过程:

(1) 检查执行器全局变量函数指针autoload_func是否为NULL。
(2) 如果autoload_func==NULL, 则查找系统中是否定义有__autoload()函数,如果没有,则报告错误并退出。
(3) 如果定义了__autoload()函数,则执行__autoload()尝试加载类,并返回加载结果。
(4) 如果autoload_func不为NULL,则直接执行autoload_func指针指向的函数用来加载类。注意此时并不检查__autoload()函数是否定义。

根据以上定义,自动加载机制在实现的时候分为两大类:__autoload,SPL autoload


(1)最简单的文件引入方式require/include:

在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进行复用,同时将来维护时也很便利。在一个脚本文件中我们需要使用到其他文件中的类时,最简单的做法就是使用require/include将类文件引入。但时当我们需要用到大量的类时,就不得不写很多的require/include语句,同时也可能会造成个别类文件的引入遗漏了。


PHP5为这个问题提供了一个解决方案,这就是类的自动加载机制。autoload机制可以使得PHP程序有可能在使用类时才自动包含类文件,而不是一开始就将所有的类文件include进来,这种机制也称为lazy loading。


(2)__autoload

void __autoload ( string$class )          你可以通过定义这个函数来启用类的自动加载。

<?php
/*下面是使用autoload机制加载Dog类的例子:*/根据注册的先后,如果在第一个注册的方法或函数里加载了类文件,就不会再执行第二个被注册的类的方法或函数。反之就会执行第二个被注册的类的方法或函数。
function __autoload($classname){
  $s=$classname.'class.php';
  require_once('./'.$s);
 }
$d=new Dog('哈巴狗',20);
?>

从这个例子中,我们可以看出 __autoload至少要做三件事情,第一件事是根据类名确定类文件名,第二件事是确定类文件所在的磁盘路径(在我们的例子是最简单的情况,类与调用它们的 PHP程序文件在同一个文件夹下),第三件事是将类从磁盘文件中加载到系统中。第三步最简单,只需要使用include/require即可。要实现第一 步,第二步的功能,必须在开发时约定类名与磁盘文件的映射方法,只有这样我们才能根据类名找到它对应的磁盘文件。那么这表明:__autoload()函数的实现中最重要的是类名与实际的磁盘文件映射规则的实现。
那么问题就来了,如果有大量开发人员参与一个项目类库的开发,或者需要引入第三方类库,这会导致类名与实际的磁盘文件映射规则有很多种,那么__autoload函数为了实现类文件的自动加载,就需要一一实现这些规则,并且还要进行大量的if-eles判断,这造成了__autoload函数的臃肿,效率低下,维护也造成不便。


(3)spl_autoload,spl_autoload_call  (手动调用)

SPL autoload机制能够很好的解决上述问题。 SPL autoload机制的实现是通过将函数指针autoload_func指向自己实现的具有自动装载功能的函数来实现的。SPL有两个不同的函数 spl_autoload, spl_autoload_call,通过将autoload_func指向这两个不同的函数地址来实现不同的自动加载机制。

1. spl_autoload:(SPL实现的默认的自动加载函数)

void spl_autoload ( string$class_name [,string$file_extensions ] )

它可以接收两个参数,第一个参数是$class_name,表示类名,第二个参 数$file_extensions是可选的,表示类文件的扩展名,多个扩展名用逗号隔开

在默认情况下,本函数先将类名转换成小写,再在小写的类名后加上 .inc 或 .php 的扩展名作为文件名,然后在所有的包含路径(include paths)中检查是否存在该文件。

常见的用法是和set_include_path,sql_autoload_extensions搭配使用

/*例子如下:MVC中实现控制器类的载入*/

public function load_controller($controller)
    {
        if ($controller) {
            set_include_path($this->controllerDirectoryPath);
            spl_autoload_extensions('.php');
            spl_autoload($class);
        }
    }   

2. spl_autoload_call

如果需要多条 autoload 函数,spl_autoload_register() 满足了此类需求。 它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。相比之下,    __autoload()只可以定义一次。

void spl_autoload_call ( string$class_name )

可以直接在程序中手动调用此函数来使用所有已注册的__autoload函数装载类或接口。


在使用spl_aulotoload_call后,系统会根据autoload函数队列中函数注册的先后,如果在第一个注册的方法或函数里加载了类文件,就不会再执行第二个被注册的类的方法或函数。反之就会执行第二个被注册的类的方法或函数。

注意:如果在你的程序中已经实现了__autoload()函数,它必须显式注册到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()spl_autoload_call()

(4) autoload效率问题及对策

使 用autoload机制时,很多人的第一反应就是使用autoload会降低系统效率,甚至有人干脆提议为了效率不要使用autoload。在我们了解了 autoload实现的原理后,我们知道autoload机制本身并不是影响系统效率的原因,甚至它还有可能提高系统效率,因为它不会将不需要的类加载到 系统中。

那么为什么很多人都有一个使用autoload会降低系统效率的印象呢?实际上,影响autoload机制效率本身恰恰是用户设计的自动加载函数。如果它 不能高效的将类名与实际的磁盘文件(注意,这里指实际的磁盘文件,而不仅仅是文件名)对应起来,系统将不得不做大量的文件是否存在(需要在每个 include path中包含的路径中去寻找)的判断,而判断文件是否存在需要做磁盘I/O操作,众所周知磁盘I/O操作的效率很低,因此这才是使得autoload机 制效率降低的罪魁祸首!

因此,我们在系统设计时,需要定义一套清晰的将类名与实际磁盘文件映射的机制。这个规则越简单越明确,autoload机制的效率就越高。























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值