PHP命名空间与自动加载机制介绍

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

PHP命名空间与⾃动加载机制介绍
include 和 require 是PHP中引⼊⽂件的两个基本⽅法。

在⼩规模开发中直接使⽤ include 和 require 没哟什么不妥,但在⼤型项⽬中会造成⼤量的include 和 require 堆积。

这样的代码既不优雅,执⾏效率也很低,⽽且维护起来也相当困难。

为了解决这个问题,部分框架会给出⼀个引⼊⽂件的配置清单,在对象初始化的时候把需要的⽂件引⼊。

但这只是让代码变得更简洁了⼀些,引⼊的效果仍然是差强⼈意。

PHP5 之后,随着 PHP ⾯向对象⽀持的完善,__autoload 函数才真正使得⾃动加载成为可能。

* include 和 require 功能是⼀样的,它们的不同在于 include 出错时只会产⽣警告,⽽ require 会抛出错误终⽌脚本。

* include_once 和 include 唯⼀的区别在于 include_once 会检查⽂件是否已经引⼊,如果是则不会重复引⼊。

=================⾃动加载==================
实现⾃动加载最简单的⽅式就是使⽤ __autoload 魔术⽅法。

当需要使⽤的类没有被引⼊时,这个函数会在PHP报错前被触发,未定义的类名会被当作参数传⼊。

⾄于函数具体的逻辑,这需要⽤户⾃⼰去实现。

⾸先创建⼀个 autoload.php 来做⼀个简单的测试:
通过这个简单的例⼦可以发现,在类的实例化过程中,系统所做的⼯作⼤致是这样的:
明⽩了 __autoload 函数的⼯作原理之后,那就让我们来⽤它去实现⾃动加载。

⾸先创建⼀个类⽂件(建议⽂件名与类名⼀致),代码如下:
(我这⾥创建了⼀个 HelloWorld 类⽤作演⽰)接下来我们就要定义 __autoload 的具体逻辑,使它能够实现⾃动加载:
=================命名空间==================
其实命名空间并不是什么新⽣事物,很多语⾔(例如C++)早都⽀持这个特性了。

只不过 PHP 起步⽐较晚,直到 PHP 5.3 之后才⽀持。

命名空间简⽽⾔之就是⼀种标识,它的主要⽬的是解决命名冲突的问题。

就像在⽇常⽣活中,有很多姓名相同的⼈,如何区分这些⼈呢?那就需要加上⼀些额外的标识。

把⼯作单位当成标识似乎不错,这样就不⽤担⼼ “撞名” 的尴尬了。

这⾥我们来做⼀个⼩任务,去介绍百度的CEO李彦宏:
↑这就是李彦宏的基本资料了,namespace 是他的单位标识,class 是他的姓名。

命名空间通过关键字 namespace 来声明。

如果⼀个⽂件中包含命名空间,它必须在其它所有代码之前声明命名空间。

↑在⼀般情况下,⽆论是向别⼈介绍 "百度李彦宏" 还是 "百度公司李彦宏",他们都能够明⽩。

在当前命名空间没有声明的情况下,限定类名和完全限定类名是等价的。

因为如果不指定空间,则默认为全局(\)。

↑如果你在⾕歌公司向他们的员⼯介绍李彦宏,⼀定要指明是 "百度公司的李彦宏"。

否则他会认为百度是⾕歌的⼀个部门,⽽李彦宏只是其中的⼀位员⼯⽽已。

这个例⼦展⽰了在命名空间下,使⽤限定类名和完全限定类名的区别。

(完全限定类名 = 当前命名空间 + 限定类名)
↑第⼀种情况是别⼈已经认识李彦宏了,你只需要直接说名字,他就能知道你指的是谁。

第⼆种情况是李彦宏就是他们的CEO,你直接说CEO,他可以⽴刻反应过来。

使⽤命名空间只是让类名有了前缀,不容易发⽣冲突,系统仍然不会进⾏⾃动导⼊。

如果不引⼊⽂件,系统会在抛出 "Class Not Found" 错误之前触发 __autoload 函数,并将限定类名传⼊作为参数。

所以上⾯的例⼦都是基于你已经将相关⽂件⼿动引⼊的情况下实现的,否则系统会抛出 " Class '百度\李彦宏' not found"。

=================spl_autoload==================
接下来让我们要在含有命名空间的情况下去实现⾃动加载。

这⾥我们使⽤ spl_autoload_register() 函数来实现,这需要你的 PHP 版本号⼤于 5.12。

spl_autoload_register 函数的功能就是把传⼊的函数(参数可以为回调函数或函数名称形式)注册到 SPL __autoload 函数队列中,并移除系统默认的
__autoload() 函数。

⼀旦调⽤ spl_autoload_register() 函数,当调⽤未定义类时,系统就会按顺序调⽤注册到 spl_autoload_register() 函数的所有函数,⽽不是⾃动调⽤
__autoload() 函数。

现在,我们来创建⼀个 Linux 类,它使⽤ os 作为它的命名空间(建议⽂件名与类名保持⼀致):
接着,在同⼀个⽬录下新建⼀个 PHP ⽂件,使⽤ spl_autoload_register 以函数回调的⽅式实现⾃动加载:
这⾥我们使⽤了⼀个数组去保存类名与⽂件路径的关系,这样当类名传⼊时,⾃动加载器就知道该引⼊哪个⽂件去加载这个类了。

但是⼀旦⽂件多起来的话,映射数组会变得很长,这样的话维护起来会相当⿇烦。

如果命名能遵守统⼀的约定,就可以让⾃动加载器⾃动解析判断类⽂件所在的
路径。

接下来要介绍的PSR-4 就是⼀种被⼴泛采⽤的约定⽅式。

=================PSR-4规范==================
PSR-4 是关于由⽂件路径⾃动载⼊对应类的相关规范,规范规定了⼀个完全限定类名需要具有以下结构:
如果继续拿上⾯的例⼦打⽐⽅的话,顶级命名空间相当于公司,⼦命名空间相当于职位,类名相当于⼈名。

那么李彦宏标准的称呼为 "百度公司 CEO 李彦宏"。

PSR-4 规范中必须要有⼀个顶级命名空间,它的意义在于表⽰某⼀个特殊的⽬录(⽂件基⽬录)。

⼦命名空间代表的是类⽂件相对于⽂件基⽬录的这⼀段路径(相对路径),类名则与⽂件名保持⼀致(注意⼤⼩写的区别)。

举个例⼦:在全限定类名 \app\view\news\Index 中,如果 app 代表 C:\Baidu,那么这个类的路径则是 C:\Baidu\view\news\Index.php
我们就以解析 \app\view\news\Index 为例,编写⼀个简单的 Demo:
通过这个 Demo 可以看出限定类名转换为路径的过程。

那么现在就让我们⽤规范的⾯向对象⽅式去实现⾃动加载器吧。

⾸先我们创建⼀个⽂件 Index.php,它处于 \app\mvc\view\home ⽬录中:
接着我们在创建⼀个加载类(不需要命名空间),它处于 \ ⽬录中:
最后,将 Loader 类中的 autoload 注册到 spl_autoload_register 函数中:
⽰例中的代码其实就是 ThinkPHP ⾃动加载器源码的精简版,它是 ThinkPHP 5 能实现惰性加载的关键。

⾄此,⾃动加载的原理已经全部讲完了,如果有兴趣深⼊了解的话,可以参考下⾯的 ThinkPHP 源码。

相关文档
最新文档