这篇文章是对PHP自动加载功能的一个总结,内容涉及PHP的自动加载功能、PHP的命名空间、PHP的PSR0与PSR4标准等内容。 一、PHP自动加载功能PHP自动加载功能的由来在php开发过程中,如果希望从外部引入一个class,通常会使用include和require方法,去把定义这个class的文件包含进来。这个在小规模开发的时候,没什么大问题。但在大型的开发项目中,使用这种方式会带来一些隐含的问题:如果一个PHP文件需要使用很多其它类,那么就需要很多的require/include语句,这样有可能会造成遗漏或者包含进不必要的类文件。如果大量的文件都需要使用其它的类,那么要保证每个文件都包含正确的类文件肯定是一个噩梦,况且require_once的代价很大。 PHP5为这个问题提供了一个解决方案,这就是类的自动装载(autoload)机制。autoload机制可以使得PHP程序有可能在使用类时才自动包含类文件,而不是一开始就将所有的类文件include进来,这种机制也称为lazyloading。 总结起来,自动加载功能带来了几处优点: 使用类之前无需include或者require 使用类的时候才会require/include文件,实现了lazyloading,避免了require/include多余文件。 无需考虑引入类的实际磁盘地址,实现了逻辑和实体文件的分离。 ?? 如果想具体详细的了解关于自动加载的功能,可以查看资料: PHP的类自动加载机制 ??PHP的autoload机制的实现解析 PHP自动加载函数__autoload()通常PHP5在使用一个类时,如果发现这个类没有加载,就会自动运行_autoload()函数,这个函数是我们在程序中自定义的,在这个函数中我们可以加载需要使用的类。下面是个简单的示例: function__autoload($classname){require_once($classname."class.php");} 在我们这个简单的例子中,我们直接将类名加上扩展名”.class.php”构成了类文件名,然后使用require_once将其加载。从这个例子中,我们可以看出autoload至少要做三件事情: 1.根据类名确定类文件名; 2.确定类文件所在的磁盘路径(在我们的例子是最简单的情况,类与调用它们的PHP程序文件在同一个文件夹下); 3.将类从磁盘文件中加载到系统中。 ??第三步最简单,只需要使用include/require即可。要实现第一步,第二步的功能,必须在开发时约定类名与磁盘文件的映射方法,只有这样我们才能根据类名找到它对应的磁盘文件。 当有大量的类文件要包含的时候,我们只要确定相应的规则,然后在__autoload()函数中,将类名与实际的磁盘文件对应起来,就可以实现lazyloading的效果。从这里我们也可以看出_autoload()函数的实现中最重要的是类名与实际的磁盘文件映射规则的实现。 __autoload()函数存在的问题如果在一个系统的实现中,如果需要使用很多其它的类库,这些类库可能是由不同的开发人员编写的,其类名与实际的磁盘文件的映射规则不尽相同。这时如果要实现类库文件的自动加载,就必须在__autoload()函数中将所有的映射规则全部实现,这样的话autoload()函数有可能会非常复杂,甚至无法实现。最后可能会导致autoload()函数十分臃肿,这时即便能够实现,也会给将来的维护和系统效率带来很大的负面影响。 那么问题出现在哪里呢?问题出现在_autoload()是全局函数只能定义一次,不够灵活,所以所有的类名与文件名对应的逻辑规则都要在一个函数里面实现,造成这个函数的臃肿。那么如何来解决这个问题呢?答案就是使用一个_autoload调用堆栈,不同的映射关系写到不同的_autoload函数中去,然后统一注册统一管理,这个就是PHP5引入的SPLAutoload。 SPLAutoloadSPL是StandardPHPLibrary(标准PHP库)的缩写。它是PHP5引入的一个扩展库,其主要功能包括autoload机制的实现及包括各种Iterator接口或类。SPLAutoload具体有几个函数: spl_autoload_register:注册__autoload()函数 spl_autoload_unregister:注销已注册的函数 spl_autoload_functions:返回所有已注册的函数 spl_autoload_call:尝试所有已注册的函数来加载类 spl_autoload:__autoload()的默认实现 spl_autoload_extionsions:注册并返回spl_autoload函数使用的默认文件扩展名。 ??这几个函数具体详细用法可见php中spl_autoload详解 简单来说,spl_autoload就是SPL自己的定义__autoload()函数,功能很简单,就是去注册的目录(由set_include_path设置)找与$classname同名的.php/.inc文件。当然,你也可以指定特定类型的文件,方法是注册扩展名(spl_autoload_extionsions)。 而spl_autoload_register()就是我们上面所说的autoload调用堆栈,我们可以向这个函数注册多个我们自己的_autoload()函数,当PHP找不到类名时,PHP就会调用这个堆栈,一个一个去调用自定义的_autoload()函数,实现自动加载功能。如果我们不向这个函数输入任何参数,那么就会注册spl_autoload()函数。 好啦,PHP自动加载的底层就是这些,注册机制已经非常灵活,但是还缺什么呢?我们上面说过,自动加载关键就是类名和文件的映射,这种映射关系不同框架有不同方法,非常灵活,但是过于灵活就会显得杂乱,PHP有专门对这种映射关系的规范,那就是PSR标准中PSR0与PSR4。 不过在谈PSR0与PSR4之前,我们还需要了解PHP的命名空间的问题,因为这两个标准其实针对的都不是类名与目录文件的映射,而是命名空间与文件的映射。为什么会这样呢?在我的理解中,规范的面向对象PHP思想,命名空间在一定程度上算是类名的别名,那么为什么要推出命名空间,命名空间的优点是什么呢 二、Namespace命名空间要了解命名空间,首先先看看官方文档中对命名空间的介绍: 什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件foo.txt可以同时在目录/home/greg和/home/other中存在,但在同一个目录中不能存在两个foo.txt文件。另外,在目录/home/greg外访问foo.txt文件时,我们必须将目录名以及目录分隔符放在文件名之前得到/home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念。 在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题: 1用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。 2为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。 PHP命名空间提供了一种将相关的类、函数和常量组合到一起的途径。 ??简单来说就是PHP是不允许程序中存在两个名字一样一样的类或者函数或者变量名的,那么有人就很疑惑了,那就不起一样名字不就可以了?事实上很多大程序依赖很多第三方库,名字冲突什么的不要太常见,这个就是北京白癜风去哪个医院白癜风医院哪里好
|