命名空间

学编程就像学开车,老司机带你装逼,带你飞 …···

命名空间

概述

背景:如果一个项目很大,有很多文件,很可能有同名的文件。这时候如果组织这些文件就成了大问题。

命名空间通过namespace声明:

1
2
3
4
5
6
7
8
namespace China;
function getInfo(){

}
namespace USA;
function getInfo(){
}
getInfo();//访问USA的getInfo

命名空间是一种封装事物的方法
命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

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

定义命名空间

受命名空间影响的是:类(包括抽象类和traits)、接口、函数和常量。
语法:namespace MyProject

必须在其它所有代码之前声明命名空间,命名空间必须是程序脚本的第一条语句。除了一个以外:declare关键字

定义子命名空间

命名空间的名字可以使用分层次的方式定义
Example #1 声明分层次的单个命名空间

1
2
3
4
5
6
<?php
namespace MyProject\Sub\Level;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

可以使用文件的路径来做命名空间。在自动加载类的时候可以通过命名空间的路径来加载类

访问空间的三种方法

  1. 非限定名称访问
  2. 完全限定名称访问
  3. [部分]限定名称访问

引入命名空间

完全限定名称访问不方便书写,可以在当前的命名空间下引入其他的命名空间,然后再使用其他命名空间的元素
通过use关键字来引入命名空间

1
2
3
4
5
6
7
8
9
10
11
namespace China\Shanghai\PuDong;
function getInfo(){
echo 'aaa';
}
namespace USA\Washington;
function getInfo(){
echo 'bb';
}
use China\Shanghai\PuDong;
getInfo(); //bb
PuDong\getInfo(); //aa

引入类(use)

引入与当前控制器同名的类会报错
解决方法:给类取别名
使用as 关键字给命名空间取别名

1
2
3
use China\Shanghai\PuDong\Person as ChinaPerson;
$person = new ChinaPerson();
echo $person->name;

引入命名空间和引入类都是用的use,他们的区分就看引入的是不是类,如果不是类就是命名空间

公共的命名空间

如果一个PHP文件中没有namespace关键字声明,则文件中的元素默认存在于公共的空间下。

在一个页面中,包含另一个文件,不会影响当前页面的命名空间

命名空间的注意事项

  1. 命名空间中可以存放:函数、类、const常量,不能存放define常量。
  2. 第一个namespace之前不能有任何代码,header()也不行
  3. 包含文件不会改变当前的命名空间

## namespace关键字和__NAMESPACE__常量
(PHP 5 >= 5.3.0, PHP 7)
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__ 魔术常量和namespace关键字

常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。

__NAMESPACE__ 示例, 在命名空间中的代码
全局代码

常量 __NAMESPACE__ 在动态创建名称时很有用

1
2
3
4
5
6
7
8
9
<?php
namespace MyProject;

function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>

允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中可以创建对其它的文件或目录的符号连接。

所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。

在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的五种导入方式的例子:

Example #1 使用use操作符导入/使用别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
namespace foo;
use My\Full\Classname as Another;

// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 导入一个全局类
use ArrayObject;

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;

$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>

通过use操作符导入/使用别名,一行中包含多个use语句
use My\Full\Classname as Another, My\Full\NSname;

名称解析示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
namespace A;
use B\D, C\E as F;
// 函数调用
foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo"
\foo(); // 调用全局空间函数 "foo"
my\foo(); // 调用定义在命名空间"A\my"中函数 "foo"
F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F"
// 类引用
new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "A\B"
new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "B\D"
new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "C\E"
new \B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B"
new \D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D"
new \F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F"
// 调用另一个命名空间中的静态方法或命名空间函数
B\foo(); // 调用命名空间 "A\B" 中函数 "foo"
B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"
D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"
\B\foo(); // 调用命名空间 "B" 中的函数 "foo"
\B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B"
// 当前命名空间中的静态方法或函数
A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"
\A\B::foo(); // 调用命名空间 "A\B" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>