PHP自动加载

2018-08-25  本文已影响0人  Think_Heart

文章总结了PHP的自动加载机制,包含魔法函数 __autoload()和spl autoload函数。

缘起

PHP开发过程中,需要通过include、include_once、require或require_once引入定义的类,如图:

<?php
require_once('./ClassA.php');
require_once('./ClassB.php');
require_once('./ClassC.php');
...

当需要引入的类比较少的时候,没有什么大问题,但是当需要引入的类非常多时,就会出现大量的include或require语句,这样会导致遗漏或者包含不必要的类文件。因此,类的自动加载(autoload)机制应运而生。
autoload机制主要用来自动加载类,该机制使PHP程序有可能在使用类时才自动引入类文件,而不是一开始就将所有的类文件引入。

自动加载函数__autoload()

PHP程序中,当我们要使用的类未导入时,会自动调用__autoload()函数,此函数是我们在程序中自定义的,通过这个函数可以加载需要引入的类。
为了更好的说明__autoload()函数,下面举个例子进行说明,以下是项目的目录:

+ first
+--   ClassA.php
+ second
+--   ClassB.php
-  autoload.php
-  index.php

首先我们来看ClassA.php:

<?php
//test/first/ClassA.php
class ClassA
{
    public  function fun()
    {
        echo "ClassA is running...\n";
    }
}

ClassB和ClassA类似,只有一个简单的函数fun():

<?php
//test/second/ClassB.php
class ClassB
{
    public  function fun()
    {
        echo "ClassB is running...\n";
    }
}

require、include函数

如果采用原始的require或者include方法,需要分别引入ClassA、ClassB文件,程序正常打印结果。

<?php
//test/index.php
require_once  __DIR__.'./first/ClassA.php';
require_once  __DIR__.'./second/ClassB.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();

__autoload()函数

为了使用__autoload()函数,我们需要单独新建一个文件,这里我们新建了一个autoload.php文件,然后在index.php文件里调用include或require引入该文件,此时当有未引入的类时,程序会自动调用__autoload()函数,并将类名作为参数传入。
__autoload()函数,首先需要确定类名对应的文件名,然后通过调用is_readable()函数判断该文件是否可读,如果可读则调用require_once引入相应的类文件。

<?php
//test/autoload.php
function __autoload($className)
{
    if($className == 'ClassA'){
        $classpath = __DIR__.'\\first\\'.$className.'.php';
    }else{
        $classpath = __DIR__.'\\second\\'.$className.'.php';
    }
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}

此时,需要修改index.php文件,该文件删掉了ClassA和ClassB的引入,同时引入了autoload.php文件。这里只需要一行即可引入所需的类,当所需的类达到数百个时,__autoload()函数的优势就会彰显无疑。另外,__autoload()函数只有在需要相应的类时才会主动引入,假设这里不需要ClassB类,那么程序不会引入。如果是采用require或include函数时,必须在程序的开始交代清楚,否则会报错。

<?php
//test/index.php
require_once  __DIR__.'./autoload.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();

但是,autoload()函数存在一个严重的缺点:__autoload() 是全局函数且只能定义一次,不够灵活。另外,所有类名和文件名的对应关系都在__autoload()函数中实现,这会导致该函数非常臃肿。

spl autoload

SPL是Standard PHP Library(标准PHP库)的缩写。它是PHP引入的一个扩展库,其主要功能包括autoload机制的实现及包括各种Iterator接口或类。其有以下几个函数:

spl_autoload_register:注册 _autoload() 函数
spl_autoload_unregister:注销已注册的_autoload()函数
spl_autoload_functions:返回所有已注册的_autoload()函数
spl_autoload_call:尝试所有已注册的_autoload()函数来加载类
spl_autoload :_autoload()函数的默认实现
spl_autoload_extionsions: 注册并返回 spl_autoload 函数使用的默认文件扩展名。

spl_autoload_register()函数实现了一个autoload调用堆栈,我们可以向这个堆栈注册多个__autoload()函数,当PHP找不到类名时,就会调用autoload堆栈,一个一个地去调用自定义的__autoload()函数,实现自动加载功能。
举例说明spl_autoload_register()函数的用法,以下是项目目录

+ first
+--   ClassA.php
+ second
+--   ClassB.php
-  autoloadA.php
-  autoloadB.php
-  index.php

项目增加了autoloadA.php、autoloadB.php文件,并且修改了index.php文件。autoloadA.php文件用于加载first文件夹下的类,autoloadB.php用于加载second文件夹下的类。通过调用spl_autoload_register()函数可以注册多个__autoload()函数。

<?php
//test/autoloadA.php
function __autoloadA($className)
{
    $classpath = __DIR__.'\\first\\'.$className.'.php';
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}
spl_autoload_register('__autoloadA');
<?php
//test/autoloadB.php
function __autoloadB($className)
{
    $classpath = __DIR__.'\\second\\'.$className.'.php';
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}
spl_autoload_register('__autoloadB');

文件index.php修改如下,此时即可以实现注册多个__autoload()函数。此时会发现,与最开始使用require或include引入文件一样需要两行才能实现所有类的引入,貌似并没有更简单。但是假设first、second文件夹下各有100个类需要引入,则使用require或include函数引入需要200行,而使用spl_autoload_register()函数引入根本不需要改变代码。

<?php
//test/index.php
require_once __DIR__ . './autoloadA.php';
require_once __DIR__ . './autoloadB.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();
上一篇 下一篇

猜你喜欢

热点阅读