PHP中命名空间基本用法以及实例

1 2019-8-20 20:59

本文实例讲述了PHP进阶学习之命名空间基本用法。分享给大家供大家参考,具体如下:

前言

命名空间(namespace),在编程语言中,是对作用域的一种特殊的抽象.它表示着一个标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他命名空间中。

在PHP中也存在命名空间的用法,由它控制可见范围的这个标识符一般指的就是类和函数。

一、PHP命名空间基础

从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如PHP的类名是不可以重复的,但是经常我们需要引入一些第三方的类库,常常类名就会在项目中产生重复冲突,所以,命名空间就是解决这个冲突的一种方法。

在PHP5.3以后,就已经引入了命名空间(namespace)的概念,即同个命名空间下的类名不能重复,不同命名空间下可以存在同名的类。

这样,在引入第三方类库的时候,只有各个类库的命名空间不一样,就不会产生冲突。

所以根据官方所说,在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

1、用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
2、为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

需要注意的是:

  • 同个文件下可以存在多个命名空间;

  • 不同命名空间内的类可以相互调用。

二、PHP命名空间的用法

1、定义

命名空间的定义采用关键字namespace,定义方式如下:

namespace example

则该命名空间下的类都归属于该命名空间,example命名空间下的类不能重名。

或者可以定义多级命名空间:

namespace example/test/demo

则改命名空间下的类全归属于example/test/demo命名空间。

定义后的命名空间可以用_​_​NAMESPACE_​_​魔法变量来获取当前命名空间。

2、引入

引入命名空间使用关键字use,可以通过多个use在一个文件中引入多个命名空间:

use example;use example/test/demo;

需要使用到哪个命名空间的类和方法,则use哪个命名空间,前提是这些命名空间的实际文件地址已经包含进来了,或者说能实现自动的类加载了。

3、实例化

在程序中实例化并使用某个命名空间下的类方法,同样使用new关键字进行实例化,但是需要在类名前面加上命名空间前缀。

例如:

$class = new example\a();//实例化example命名空间下的a类
$class = new example\test\demo\b(); //实例化example\test\demo命名空间下的b类

如果在文件前面已经引入了这些命名空间,则可以不需要类的前缀:

use example;
use example\test\demo;
$class = new a();//实例化example命名空间下的a类
$class = new b(); //实例化example\test\demo命名空间下的b类

注:如果use的时候是use example/test;则在实例化b类时要带上相对命名空间路径(注意不是实际文件路径),即new demo/b();

当然所有的实例化都可以直接使用绝对路径形式,即在命名空间前面加/字符,如new /example/test/demo/b();这样就采用了绝对路径形式实例化了b类。

4、别名

在用namespace定义命名空间的时候,为了避免之后引用的时候命名空间过长,可以在定义时采用as关键字为一个命名空间指定别名

namespace example/test/demo as testDemo;

这样在之后引用或实例化的时候就可以new testDemo/<类名>();

三、基于PSR4的命名空间规范

由于方法、类在不同项目中命名空间定义不一致,第三方类库的命名空间也定义不一致,所以相关php组织出台了一套约定俗成的规范,即PSR4规范,

用来规范命名空间的定义规则。

具体规范如下:

1. 一个完整的类名需具有以下结构:

/<命名空间>(/<子命名空间>)*/<类名>
    1. 完整的类名 必须 要有一个顶级命名空间,被称为 "vendor namespace";
    2. 完整的类名 可以 有一个或多个子命名空间;
    3. 完整的类名 必须 有一个最终的类名;
    4. 完整的类名中任意一部分中的下滑线都是没有特殊含义的;
    5. 完整的类名 可以 由任意大小写字母组成;
    6. 所有类名都 必须 是大小写敏感的。

2. 当根据完整的类名载入相应的文件

    (1). 完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,作为「命名空间前缀」,其必须与至少一个「文件基目录」相对应;
    (2). 紧接命名空间前缀后的子命名空间 必须 与相应的「文件基目录」相匹配,其中的命名空间分隔符将作为目录分隔符。
    (3). 末尾的类名 必须 与对应的以 .php 为后缀的文件同名。
    (4). 自动加载器(autoloader)的实现 一定不可 抛出异常、一定不可 触发任一级别的错误信息以及 不应该 有返回值。

看起来很复杂,其实规范的要点就是,命名空间的路径要与当前文件的路径相对应,这样规范了所有项目命名空间的定义准则,虽然PHP官方没有

强制规定,但如今许多开源项目都已经约定俗成地使用了,这种规范便于查找命名空间下的类所在的路径。

例如,文件目录a/b/c下有d.php,则在a目录下的的文件引入d的类时,应该是use b/c或use /a/b/c;(绝对路径形式)

四、注意点

1、代码复用类Trait也符合命名空间的规范,即通过命名空间下Trait类不能重名;
2、虽然PSR4规定了命名空间路径与文件路径需要相对应,但是运行php时命名空间路径与文件路径是没有任何关系的,例如a/b/c下的文件类d,命名空间可以写成a1/b1/c1/d;只不过现在的许多开源框架在实现类自动加载的时候把两者规范为一致,否则会出现类文件加载到了,但是命名空间却加载不到的情况。
3、在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间A/B内部调用C/D/e(),则C/D/e()会被转换为A/B/C/D/e()。
4、在命名空间内部(例如A/B),对非限定名称的函数调用是在运行时解析的。例如对函数foo()的调用是这样解析的:
(1)在当前命名空间中查找名为A/B/foo()的函数
(2)尝试查找并调用全局(global)空间中的函数foo()。
5、在命名空间(例如A/B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用new C()及new D/E()的解析过程:new C()的解析:
(1)在当前命名空间中查找A/B/C类。
(2)尝试自动装载类A/B/C。

以上内容引用了PSR4文档地址:http://www.php-fig.org/psr/psr-4/

希望本文所述对大家PHP程序设计有所帮助。