码迷,mamicode.com
首页 > Web开发 > 详细

php 自动加载函数、自动加载方法、自动加载类

时间:2015-11-13 06:17:01      阅读:343      评论:0      收藏:0      [点我收藏+]

标签:

在PHP开发过程中,如果希望从 外部引入一个class,通常会使用include和require方法,去把定义这个class的文件包含进来。这个在小规模开发的时候,没什么大问 题。但在大型的开发项目中,这么做会产生大量的require或者include方法调用,这样不因降低效率,而且使得代码难以维护,况且 require_once的代价很大。

在PHP5之前,各个PHP框架如果要实现类的自动加载,一般都是按照某种约定自己实现一个遍历 目录,自动加载所有符合约定规则的文件的类或函数。 当然,PHP5之前对面向对象的支持并不是太好,类的使用也没有现在频繁。 在PHP5后,当加载PHP类时,如果类所在文件没有被包含进来,或者类名出错,Zend引擎会自动调用__autoload 函数。此函数需要用户自己实现__autoload函数。 在PHP5.1.2版本后,可以使用spl_autoload_register函数自定义自动加载处理函数。当没有调用此函数,默认情况下会使用SPL 自定义的spl_autoload函数。

spl_autoload函数的默认实现 如果不使用任何参数调用 autoload_register() 函数,则以后在进行 __autoload() 调用时会自动使用此函数。

SPL有两个不同的函数 spl_autoload, spl_autoload_call,通过将autoload_func指向这两个不同的函数地址来实现不同的自动加载机制。

spl_autoload 是SPL实现的默认的自动加载函数,它的功能比较简单。它可以接收两个参数,第一个参数是$class_name,表示类名,第二个参 数$file_extensions是可选的,表示类文件的扩展名" title="扩展名">扩展名,可以在$file_extensions中指定多个扩展名" title="扩展名">扩展名,护展名之间用分号隔开即 可;如果不指定的话,它将使用默认的扩展名" title="扩展名">扩展名.inc或.php。spl_autoload首先将$class_name变为小写,然后在所有的 include path中搜索$class_name.inc或$class_name.php文件(如果不指定$file_extensions参数的话),如果找 到,就加载该类文件。你可以手动使用spl_autoload(”Person”, “.class.php”)来加载Person类。实际上,它跟require/include差不多,不同的它可以指定多个扩展名" title="扩展名">扩展名。

怎 样让spl_autoload自动起作用呢,也就是将autoload_func指向spl_autoload?答案是使用 spl_autoload_register函数。在PHP脚本中第一次调用spl_autoload_register()时不使用任何参数,就可以将 autoload_func指向spl_autoload。

通过上面的说明我们知道,spl_autoload的功能比较简单,而且它是在SPL扩展中实现的,我们无法扩充它的功能。如果想实现自己的更灵活的自动加载机制怎么办呢?这时,spl_autoload_call函数闪亮登场了。

我 们先看一下spl_autoload_call的实现有何奇妙之处。在SPL模块内部,有一个全局变量autoload_functions,它本质上是 一个HashTable,不过我们可以将其简单的看作一个链表,链表中的每一个元素都是一个函数指针,指向一个具有自动加载类功能的函数。 spl_autoload_call本身的实现很简单,只是简单的按顺序执行这个链表中每个函数,在每个函数执行完成后都判断一次需要的类是否已经加载, 如果加载成功就直接返回,不再继续执行链表中的其它函数。如果这个链表中所有的函数都执行完成后类还没有加载,spl_autoload_call就直接 退出,并不向用户报告错误。因此,使用了autoload机制,并不能保证类就一定能正确的自动加载,关键还是要看你的自动加载函数如何实现。

在php5中的标准库方法spl_autoload相当于实现自己的__autoload

<?php

    function __autoload($classname){

        if(is_file($classname.‘.php‘){

            include $classname.‘.php‘;

        } elseif(is_file($classname.‘.inc‘){

            include $classname.‘.inc‘;

        }

    }

 它会在注册目录下自动寻找与$classname同名的.php/.inc文件。当然,你也可以指定特定类型的文件,方法是注册扩展名

<?php

    spl_autoload_extensions(‘.php,.inc,.some‘);

 这样,它也会搜索.some文件。默认,php是不会启动spl_autoload的,那么怎样才能自动让spl_autoload生效呢呢?方法是

<?php

    spl_autoload_register();

 spl_autoload_register有一个$callback参数,如果不指定,它就会自动注册spl_autoload,为了能搜寻更多的自动加载目录,可以在这些代码前面设置自动加载目录

<?php

    set_include_path(get_include_path() . PATH_SEPARATOR . ‘some/path‘ . DIRECTORY_SEPARATOR);

 

这样,当php找不到指定的类时,就会在set_include_path指定的目录下寻找。

这些方法常用在php框架中。比如把上面的介绍串连起来:

<?php

set_include_path(get_include_path() . PATH_SEPARATOR . ‘some/path‘ . DIRECTORY_SEPARATOR);

spl_autoload_extensions(‘.php,.inc,.some‘);

spl_autoload_register();

 当你要加载some/path下面的classA类时,它会在目录下寻找classa.php或classa.inc或classa.some,这样你就可以放心地运用new classA或extends classA

<?php

    ClassB extends ClassA {

        // code..

    }  
     $a = new ClassA;

    $b = new ClassB;

 

 

 

spl_autoload

spl_autoload_register 注册一个自动加载函数 函数参数一个当类不存在时自动加载的函数

spl_autoload_call尝试调用所有已注册的自动加载函数来装载请求类

spl_autoload_extensions注册并返回spl_autoload函数使用的默认文件扩展名。当不使用任何参数调用此函数时,它返回当前的文件扩展名的列表,不同的扩展名用逗号分隔。要修改文件扩展名列表,用一个逗号分隔的新的扩展名列表字符串来调用本函数即可。中文注:默认的spl_autoload函数使用的扩展名是".inc,.php"。实例:spl_autoload_extensions(".inc, .php, .lib, .lib.php ");

spl_autoload_unregister注销已注册的自动加载函数  函数参数注册时的函数名

spl_autoload_functions 返回所有已注册的z自动加载函数函数。

 

 

 

1、 __autoload示例:

    function __autoload($class_name) {  
       echo ‘__autload class:‘, $class_name, ‘<br />‘;  
    }  
      
    new Demo();  

 

以上的代码在最后会输出:__autload class:Demo。
并在此之后报错显示: Fatal error: Class ‘Demo’ not found

我们一般使用_autoload自动加载类如下:

    <?php   
      
      function __autoload($class_name) {   
           require_once ($class_name . “class.php”);   
      }   
       $memo= new Demo();    

 

我们可以看出_autoload至少要做三件事情,第一件事是根据类名确定类文件名,第二件事是 确定类文件所在的磁盘路径(在我们的例子是最简单的情况,类与调用它们的PHP程序文件在同一个文件夹下),第三件事是将类从磁盘文件中加载到系统中。第 三步最简单,只需要使用include/require即可。要实现第一步,第二步的功能,必须在开发时约定类名与磁盘文件的映射方法,只有这样我们才能 根据类名找到它对应的磁盘文件。 

因此,当有大量的类文件要包含的时候,我们只要确定相应的规则,然后在__autoload() 函数中,将类名与实际的磁盘文件对应起来,就可以实现lazy loading的效果。从这里我们也可以看出__autoload()函数的实现中最重要的是类名与实际的磁盘文件映射规则的实现。 

但现在问题来了,假如在一个系统的实现中,假如需要使用很多其它的类库,这些类库可能是由不同的 开发工程师开发,其类名与实际的磁盘文件的映射规则不尽相同。这时假如要实现类库文件的自动加载,就必须在__autoload()函数中将所有的映射规 则全部实现,因此__autoload()函数有可能会非常复杂,甚至无法实现。最后可能会导致__autoload()函数十分臃肿,这时即便能够实 现,也会给将来的维护和系统效率带来很大的负面影响。在这种情况下,一种新的解决方案,即spl_autoload_register()函数。

2、此函数的功能就是把函数注册至SPL的__autoload函数栈中,并移除系统默认的__autoload()函数。下面的例子可以看出:

function __autoload($class_name) {  
    echo ‘__autload class:‘, $class_name, ‘<br />‘;  
}  
function classLoader($class_name) {  
    echo ‘SPL load class:‘, $class_name, ‘<br />‘;  
}  
spl_autoload_register(‘classLoader‘);  
new Test();//结果:SPL load class:Test 

 语法:bool  spl_autoload_register ( [callback $autoload_function] )    接受两个参数:一个是添加到自动加载栈的函数,另外一个是加载器不能找到这个类时是否抛出异常的标志。第一个参数是可选的,并且默认指向 spl_autoload()函数,这个函数会自动在路径中查找具有小写类名和.php扩展或者.ini扩展名,或者任何注册到 spl_autoload_extensions()函数中的其它扩展名的文件。

    <?php    
    class CalssLoader     
    {     
        public static function loader($classname)     
        {     
            $class_file = strtolower($classname).".php";     
            if (file_exists($class_file)){     
                require_once($class_file);     
            }     
        }     
    }      
    // 方法为静态方法     
    spl_autoload_register(‘CalssLoader::loader‘);      
    $test = new Test();  

 一旦调用spl_autoload_register()函数,当调用未定义类时,系统会按顺序调用注册到spl_autoload_register()函数的所有函数,而不是自动调用__autoload()函数。如果要避免这种情况,需采用一种更加安全的spl_autoload_register()函数的初始化调用方法:

    if(false === spl_autoload_functions()){      
        if(function_exists(‘__autoload‘)){      
            spl_autoload_registe(‘__autoload‘,false);      
        }      
     }     

 

spl_autoload_functions()函数会返回已注册函数的一个数组,如果SPL自动加载栈还没有被初始化,它会返回布尔值false。然 后,检查是否有一个名为__autoload()的函数存在,如果存在,可以将它注册为自动加载栈中的第一个函数,从而保留它的功能。之后,可以继续注册 自动加载函数。

还可以调用spl_autoload_register()函数以注册一个回调函数,而不是为函数提供一个字符串名称。如提供一个如array(‘class‘,‘method‘)这样的数组,使得可以使用某个对象的方法。

下一步,通过调用spl_autoload_call(‘className‘)函数,可以手动调用加载器,而不用尝试去使用那个类。这个函数可以和函数 class_exists(‘className‘,false)组合在一起使用以尝试去加载一个类,并且在所有的自动加载器都不能找到那个类的情况下失 败。

f(spl_autoload_call(‘className‘) && class_exists(‘className‘,false)){      
    
    } else {      
    }  

 SPL 自动加载功能是由spl_autoload() ,spl_autoload_register(), spl_autoload_functions() ,spl_autoload_extensions()和spl_autoload_call()函数提供的。

php 自动加载函数、自动加载方法、自动加载类

标签:

原文地址:http://www.cnblogs.com/xuexikun/p/4960775.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!