命名空间
namespace在C++里见过,use namespace std;
命名空间可以解决两类问题
- 用户编写的代码与PHP内部的类/常量/函数或第三方类/函数/常量之间的名字冲突
- 为很长的标识符名称创建一个别名或简称,提高代码的可读性
定义命名空间
默认情况下,所有常量,函数和类都放在全局空间下,就和PHP支持命名空间之前一样
命名空间使用namespace关键字来声明。如果一个文件中包含命名空间,它必须在其他所有代码之前声明命名空间
语法1
2
3
4
5
// 定义代码在 'MyProject' 命名空间中
namespace MyProject;
// ... 代码 ...
你也可以在同一个文件中定义不同的命名空间代码1
2
3
4
5
6
7
8
9
10
11
12
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
这种写法一般是不建议的,所以为了提高代码的可读性,使用大括号的形式
1 |
|
将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。且全局代码必须用一个不带名称的namespace语句加上大括号括起来
1 |
|
在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的declare语句。所有非PHP代码包括空白符都不能出现在命名空间的声明之前1
2
3
4
5
6
7
8
9
10
11
12
13
14
declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
如果写成这样就会出现语法错误
1 | <html> |
子命名空间
与目录和文件的关系很像,PHP命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义
1 |
|
类似于目录结构
命名空间使用
PHP命名空间中的类名可以通过三种方式引用
非限定名称,或不包含前缀的类名称,例如$a=new foo();或foo::staticmethod();
限定名称,或包含前缀的名称,例如$a=new subnamespace\foo();或subnamespace\foo::staticmethod();
完全限定名称,或包含了全局前缀操作符的名称,例如,$a=new\currentnamespace\foo();
下面便是三种方式的实例
file1.php1
2
3
4
5
6
7
8
9
namespace Foo\Bar\subnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
file2.php1
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
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* 非限定名称 */
foo(); // 解析为函数 Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod
echo FOO; // 解析为常量 Foo\Bar\FOO
/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
// 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO
/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
注意访问任意全局类,函数或常量,都可以使用完全限定名称
在命名空间内部访问全局类,函数和常量1
2
3
4
5
6
7
8
9
10
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // 调用全局函数strlen
$b = \INI_ALL; // 访问全局常量 INI_ALL
$c = new \Exception('error'); // 实例化全局类 Exception
命名空间和动态语言特征
PHP命名空间的实现受到其语言自身的动态特征影响。因此,如果要将下面的代码转换到命名空间中,动态访问元素
1 |
|
必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的
1 |
|
namespace关键字和_NAMESPACE_常量
PHP支持两种抽象的访问当前命名空间内部元素的方法,NAMESPACE 魔术常量和namespace关键字。
常量NAMESPACE的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
1 |
|
使用_NAMESPACE_动态创建名称1
2
3
4
5
6
7
8
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
全局空间
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
1 |
|
总结
1.命名空间的存在增加了代码的灵活度,可以更好的编写程序
2.命名空间的使用基本与文件目录相似,都是使用\
来进行划分,如果只有一个\
那就默认为是全局空间,不加也可以
3.完全命名空间可以看成是完整的绝对路径,而不完全的基本上可以看成是相对路径