发布于 2016-11-18 14:14:23 | 210 次阅读 | 评论: 1 | 来源: 网络整理
PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物。 不过在PHP当中还是有着相当重要的意义。
PHP 命名空间可以解决以下两类问题:
默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。
命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。语法格式如下;
< ?php
// 定义代码在 'MyProject' 命名空间中
namespace MyProject;
// ... 代码 ...
你也可以在同一个文件中定义不同的命名空间代码,如:
< ?php
namespace MyProject1;
// MyProject1 命名空间中的PHP代码
namespace MyProject2;
// MyProject2 命名空间中的PHP代码
// 另一种语法
namespace MyProject3 {
// MyProject3 命名空间中的PHP代码
}
?>
在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
<?php
declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProjectconnect();
echo MyProjectConnection::start();
}
?>
以下代码会出现语法错误:
<html>
<?php
namespace MyProject; // 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
?>
与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
<?php
namespace MyProjectSubLevel; //声明分层次的单个命名空间
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>
上面的例子创建了常量 MyProjectSubLevelCONNECT_OK,类 MyProjectSubLevelConnection 和函数 MyProjectSubLevelConnection。
PHP 命名空间中的类名可以通过三种方式引用:
下面是一个使用这三种方式的实例:
file1.php 文件代码
<?php
namespace FooBarsubnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
file2.php 文件代码
<?php
namespace FooBar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* 非限定名称 */
foo(); // 解析为 FooBarfoo resolves to function FooBarfoo
foo::staticmethod(); // 解析为类 FooBarfoo的静态方法staticmethod。resolves to class FooBarfoo, method staticmethod
echo FOO; // resolves to constant FooBarFOO
/* 限定名称 */
subnamespacefoo(); // 解析为函数 FooBarsubnamespacefoo
subnamespacefoo::staticmethod(); // 解析为类 FooBarsubnamespacefoo,
// 以及类的方法 staticmethod
echo subnamespaceFOO; // 解析为常量 FooBarsubnamespaceFOO
/* 完全限定名称 */
FooBarfoo(); // 解析为函数 FooBarfoo
FooBarfoo::staticmethod(); // 解析为类 FooBarfoo, 以及类的方法 staticmethod
echo FooBarFOO; // 解析为常量 FooBarFOO
?>
注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如 strlen() 或 Exception 或 INI_ALL。
在命名空间内部访问全局类、函数和常量:
<?php
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 命名空间的实现受到其语言自身的动态特征的影响。因此,如果要将下面的代码转换到命名空间中,动态访问元素。
example1.php 文件代码:
<?php
class classname
{
function __construct()
{
echo __METHOD__,"n";
}
}
function funcname()
{
echo __FUNCTION__,"n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "n"; // prints global
?>
必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。
动态访问命名空间的元素
<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"n";
}
}
function funcname()
{
echo __FUNCTION__,"n";
}
const constname = "namespaced";
include 'example1.php';
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "n"; // prints global
/* note that if using double quotes, "\namespacename\classname" must be used */
$a = 'namespacenameclassname';
$obj = new $a; // prints namespacenameclassname::__construct
$a = 'namespacenameclassname';
$obj = new $a; // also prints namespacenameclassname::__construct
$b = 'namespacenamefuncname';
$b(); // prints namespacenamefuncname
$b = 'namespacenamefuncname';
$b(); // also prints namespacenamefuncname
echo constant('namespacenameconstname'), "n"; // prints namespaced
echo constant('namespacenameconstname'), "n"; // also prints namespaced
?>
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__ 魔术常量和namespace关键字。
常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
__NAMESPACE__ 示例, 在命名空间中的代码
<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>
__NAMESPACE__ 示例,全局代码
<?php
echo '"', __NAMESPACE__, '"'; // 输出 ""
?>
常量 __NAMESPACE__ 在动态创建名称时很有用,例如:
使用__NAMESPACE__动态创建名称
<?php
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\' . $classname;
return new $a;
}
?>
关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中的 self 操作符。
amespace操作符,命名空间中的代码
<?php
namespace MyProject;
use blahblah as mine; // see "Using namespaces: importing/aliasing"
blahmine(); // calls function blahblahmine()
namespaceblahmine(); // calls function MyProjectblahmine()
namespacefunc(); // calls function MyProjectfunc()
namespacesubfunc(); // calls function MyProjectsubfunc()
namespacecname::method(); // calls static method "method" of class MyProjectcname
$a = new namespacesubcname(); // instantiates object of class MyProjectsubcname
$b = namespaceCONSTANT; // assigns value of constant MyProjectCONSTANT to $b
?>
namespace操作符, 全局代码
<?php
namespacefunc(); // calls function func()
namespacesubfunc(); // calls function subfunc()
namespacecname::method(); // calls static method "method" of class cname
$a = new namespacesubcname(); // instantiates object of class subcname
$b = namespaceCONSTANT; // assigns value of constant CONSTANT to $b
?>
PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。注意PHP不支持导入函数或常量。
在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的三种导入方式的例子:
1、使用use操作符导入/使用别名
<?php
namespace foo;
use MyFullClassname as Another;
// 下面的例子与 use MyFullNSname as NSname 相同
use MyFullNSname;
// 导入一个全局类
use ArrayObject;
$obj = new namespaceAnother; // 实例化 fooAnother 对象
$obj = new Another; // 实例化 MyFullClassname 对象
NSnamesubnsfunc(); // 调用函数 MyFullNSnamesubnsfunc
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use ArrayObject" ,则实例化一个 fooArrayObject 对象
?>
2、 一行中包含多个use语句
<?php
use MyFullClassname as Another, MyFullNSname;
$obj = new Another; // 实例化 MyFullClassname 对象
NSnamesubnsfunc(); // 调用函数 MyFullNSnamesubnsfunc
?>
导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。
3、导入和动态名称
<?php
use MyFullClassname as Another, MyFullNSname;
$obj = new Another; // 实例化一个 MyFullClassname 对象
$a = 'Another';
$obj = new $a; // 实际化一个 Another 对象
?>
另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
4、导入和完全限定名称
<?php
use MyFullClassname as Another, MyFullNSname;
$obj = new Another; // instantiates object of class MyFullClassname
$obj = new Another; // instantiates object of class Another
$obj = new Anotherthing; // instantiates object of class MyFullClassnamething
$obj = new Anotherthing; // instantiates object of class Anotherthing
?>
在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称,例如:
1、在命名空间中访问全局类
<?php
namespace ABC;
class Exception extends Exception {}
$a = new Exception('hi'); // $a 是类 ABCException 的一个对象
$b = new Exception('hi'); // $b 是类 Exception 的一个对象
$c = new ArrayObject; // 致命错误, 找不到 ABCArrayObject 类
?>
对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
2、 命名空间中后备的全局函数/常量
<?php
namespace ABC;
const E_ERROR = 45;
function strlen($str)
{
return strlen($str) - 1;
}
echo E_ERROR, "n"; // 输出 "45"
echo INI_ALL, "n"; // 输出 "7" - 使用全局常量 INI_ALL
echo strlen('hi'), "n"; // 输出 "1"
if (is_array('hi')) { // 输出 "is not array"
echo "is arrayn";
} else {
echo "is not arrayn";
}
?>
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
使用全局空间说明
<?php
namespace ABC;
/* 这个函数是 ABCfopen */
function fopen() {
/* ... */
$f = fopen(...); // 调用全局的fopen函数
return $f;
}
?>
自从有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的了。
<?php
namespace A;
use BD, CE as F;
// 函数调用
foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo"
foo(); // 调用全局空间函数 "foo"
myfoo(); // 调用定义在命名空间"Amy"中函数 "foo"
F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F"
// 类引用
new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "AB"
new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "BD"
new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "CE"
new B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B"
new D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D"
new F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F"
// 调用另一个命名空间中的静态方法或命名空间函数
Bfoo(); // 调用命名空间 "AB" 中函数 "foo"
B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "AB" ,则尝试自动装载类 "AB"
D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "BD" 未找到,则尝试自动装载类 "BD"
Bfoo(); // 调用命名空间 "B" 中的函数 "foo"
B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B"
// 当前命名空间中的静态方法或函数
AB::foo(); // 调用命名空间 "AA" 中定义的类 "B" 的 "foo" 方法
// 如果类 "AAB" 未找到,则尝试自动装载类 "AAB"
AB::foo(); // 调用命名空间 "AB" 中定义的类 "B" 的 "foo" 方法
// 如果类 "AB" 未找到,则尝试自动装载类 "AB"
?>
名称解析遵循下列规则: