前言开始之前请关注我自己的博客:www.leoyang90.cn本文是对PHP自动加载功能的总结,涉及到PHP的自动加载功能和PHP的命名空间,PHP的PSR0和PSR4标准等一、PHP自动加载功能PHP自动加载功能的由来在PHP开发过程中,如果要从外部引入一个类,通常会使用include和require方法来包含定义这个类的文件.这在小规模开发时问题不大。但是在大型开发项目中,使用这种方式会带来一些隐患:如果一个PHP文件需要使用很多其他的类,那么就需要大量的require/include语句,可能会造成遗漏或者include不需要的类文件。如果大量的文件需要使用其他类,要确保每个文件都包含正确的类文件肯定是一场噩梦,而且require_once非常昂贵。PHP5为这个问题提供了一个解决方案,就是类的自动加载机制。自动加载机制可以使PHP程序在使用类时自动包含class文件,而不是一开始就包含所有的class文件。这种机制也称为延迟加载。总结一下,自动加载功能带来了几个好处:在使用类之前,使用类时不需要include和require。只使用require/include文件,实现懒加载,避免require/include冗余文件。无需考虑导入类的实际磁盘地址,实现了逻辑和实体文件的分离。如果想详细了解autoloading的功能,可以查看资料:PHP类自动加载机制PHP的autoload机制实现分析PHP自动加载函数__autoload()通常在PHP5使用一个类的时候,如果发现这个类做不加载后,会自动运行_autoload()函数。该功能是在程序中自定义的。在这个函数中,我们可以加载我们需要使用的类。这是一个简单的例子:function__autoload($classname){require_once($classname."class.php");在我们这个简单的例子中,我们只是简单地添加扩展名为“.class.php”的类名,形成指定的类文件名,然后使用require_once来加载它。从这个例子我们可以看出autoload至少要做三件事:根据类名确定类文件名;确定类文件所在的磁盘路径(在我们的示例中是最简单的情况,类和调用它们的PHP程序文件在同一个文件夹中);将磁盘文件中的类加载到系统中。第三步最简单,只需要使用include/require。要实现第一步和第二步的功能,开发时必须约定好类名与磁盘文件的映射方式,这样才能根据类名找到对应的磁盘文件。当有大量类文件需要被包含时,我们只需要确定相应的规则,然后在__autoload()函数中,将类名与实际磁盘文件进行匹配即可达到延迟加载的效果。从这里我们也可以看出,_autoload()函数的实现中最重要的是类名和实际磁盘文件映射规则的实现。__autoload()函数的问题如果在一个系统的实现中需要用到很多其他的类库,这些类库可能是由不同的开发者编写的,类名与实际磁盘文件的映射规则是不一样的.这时候如果要实现类库文件的自动加载,就必须在__autoload()函数中实现所有的映射规则。在这种情况下,autoload()函数可能会非常复杂,甚至无法实现。最后,autoload()函数可能会非常臃肿。即使此时能够实现,也会对以后的维护和系统效率产生很大的负面影响。那么问题出在哪里呢?问题是_autoload()是一个全局函数,只能定义一次,不够灵活,所以所有类名和文件名对应的逻辑规则都必须在一个函数中实现,导致函数臃肿。那么如何解决这个问题呢?答案就是使用一个_autoload调用栈,将不同的映射关系写到不同的_autoload函数中,然后统一注册管理。这是PHP5引入的SPLAutoload。SPLAutoloadSPL是StandardPHPLibrary(标准PHP库)的缩写。它是PHP5引入的一个扩展库。其主要功能包括自动加载机制的实现和各种Iterator接口或类。SPLAutoload有几个具体的函数:spl_autoload_register:注册__autoload()函数spl_autoload_unregister:注销注册的函数spl_autoload_functions:返回所有注册的函数spl_autoload_call:尝试所有注册的函数加载类spl_autoload:__autoload()的默认实现spl_autoload_extions:注册并返回spl_autoload函数使用的默认文件扩展名。这些函数的详细用法可以参考php中spl_autoload的详解。简而言之,spl_autoload是SPL自己定义的__autoload()函数。/.inc文件。当然你也可以通过注册扩展名(spl_autoload_extions)来指定具体的文件类型。而spl_autoload_register()就是我们上面提到的autoload调用栈。我们可以向这个函数注册多个我们自己的_autoload()函数。当PHP找不到类名时,PHP会调用这个栈,一个一个调用。调用自定义的_autoload()函数实现自动加载功能。如果我们不向该函数传递任何参数,那么spl_autoload()函数将被注册。嗯,这些是PHP自动加载的底层。注册机制已经很灵活了,还缺少什么呢?上面我们说了,自动加载的关键是类名和文件的映射。不同的框架对这种映射关系有不同的处理方式,非常灵活,但是如果过于灵活,就会显得杂乱无章。PHP对这种映射关系有一个规范,即PSRStandardPSR0和PSR4。不过,在讲PSR0和PSR4之前,我们需要了解一下PHP的命名空间问题,因为这两个标准并不是针对类名和目录文件的映射,而是针对命名空间和文件的映射。为什么会这样?在我的理解中,标准的面向对象的PHP思想,命名空间在一定程度上是类名的别名,那么为什么要引入命名空间,命名空间有什么优点2、Namespace命名空间要理解命名空间,首先First看看官方文档中关于命名空间的介绍:什么是命名空间?从广义上讲,命名空间是一种封装事物的方式。这种抽象可以在很多地方看到。例如,目录在操作系统中用于对相关文件进行分组,它充当目录中文件的名称空间。例如,文件foo.txt可以同时存在于/home/greg和/home/other目录下,但两个foo.txt文件不能存在于同一个目录下。另外,访问/home/greg目录外的foo.txt文件时,必须在文件名前加上目录名和目录分隔符,才能得到/home/greg/foo.txt。将这一原则应用到编程领域就是命名空间的概念。在PHP中,命名空间用于解决在编写类库或应用程序时创建类或函数等可重用代码时遇到的两类问题:三方类/函数/常量之间的名称冲突2为非常长的标识符创建一个(或简称)名称名称(通常定义为缓解第一类问题),提高源代码的可读性。PHP名称空间提供了一种将相关的类、函数和常量组合在一起的方法。简单的说,PHP不允许程序中两个类或者函数或者变量名同名,所以有些人很疑惑,为什么不直接重名呢?其实很多大程序都依赖很多第三方库,名字冲突应该不会太常见。这是官网上的第一个问题。那么如何解决这个问题呢?在没有命名空间的情况下,可怜的程序员只能像a_b_c_d_e_f这样命名类,其中a/b/c/d/e/f一般都有其特定的含义,所以一般不会有冲突,但是这么长的类名写起来很累甚至更难阅读。所以PHP5引入了命名空间,类名就是类名,命名空间就是命名空间。程序编写/查看时,直接使用类名,机器运行时查看命名空间,解决问题。此外,命名空间提供了一种将相关类、函数和常量组合在一起的方法。这也是面向对象语言命名空间的一大用途。将特定用途所需的类、变量和函数写入命名空间进行封装。解决了类名问题,我们终于可以回到PSR标准,那么PSR0和PSR4是如何规范文件和命名空间的映射关系的呢?答案是:命名空间的命名(数量,有点绕)、类文件目录的位置、两者的映射关系都有限制。这是标准的核心。更完整的描述参见现代PHP新特性系列(一)——命名空间3.PSR标准在讲PSR0和PSR4之前,先介绍一下PSR标准。PSR标准的发明者和制定者是:PHP-FIG,其网址是:www.php-fig.org。正是这个联盟发明并创建了PSR规范。FIG是FrameworkInteroperabilityGroup(框架互操作性组织)的缩写。它由几位开源框架的开发人员于2009年创立。从那时起,许多其他成员被选中。虽然它不是一个“官方”组织,但它也代表了社区的一小部分。组织的宗旨是:以最低限度的限制统一各个项目的编码标准,避免各个公司自研风格阻碍程序员发展的麻烦,所以大家发明总结了PSR,PSR正在提出标准建议(RecommendationsforStandards的缩写)。具体详细的规范标准可以查看PHP中的PSR规范PSR0。标准的PRS-0规范是他们的第一套规范。主要制定了一些自动加载标准(AutoloadingStandard)PSR-0的强制性要求:1.一个完全限定的命名空间和类必须符合这个结构:“
