命名空间用来解决:用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。为很长的标识符名称创建一个别名(或简短)的名称,提高源代码的可读性。
虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口、函数和常量。
如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字,用于定义源文件编码方式的 declare 语句。代码包括空白符都不能出现在命名空间的声明之前。
与PHP其它的语言特征不同,同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。
<?phpnamespace MyProject\Sub\Level;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() {/* ... */ }
<?phpnamespace MyProject;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }namespace AnotherProject;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }
不建议使用这种语法在单个文件中定义多个命名空间。建议使用下面的大括号形式的语法。
<?phpnamespace MyProject {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ } }namespace AnotherProject {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ } }
在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。
将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来.
非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。
限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo。
完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。
注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen() 或 \Exception 或 \INI_ALL。
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__
魔术常量和namespace关键字。
__NAMESPACE__
可以表示字符串,其他的和namesapce一样。
使用use操作符导入/使用别名
<?phpnamespace 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\functionNameecho CONSTANT; // echoes the value of My\Full
通过use操作符导入/使用别名,一行中包含多个use语句
<?phpuse My\Full\Classname as Another, My\Full\NSname;$obj = new Another; // 实例化 My\Full\Classname 对象NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
导入和动态名称
导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。
<?phpuse My\Full\Classname as Another, My\Full\NSname;$obj = new Another; // 实例化一个 My\Full\Classname 对象$a = 'Another';$obj = new $a; // 实际化一个 Another 对象
导入和完全限定名称
导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
<?phpuse My\Full\Classname as Another, My\Full\NSname;$obj = new Another; // instantiates object of class My\Full\Classname$obj = new \Another; // instantiates object of class Another$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing$obj = new \Another\thing; // instantiates object of class Another\thing
<?phpnamespace A\B\C;/* 这个函数是 A\B\C\fopen */function fopen() { /* ... */ $f = \fopen(...); // 调用全局的fopen函数 return $f; }
在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称。对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
<?phpnamespace A\B\C;class Exception extends \Exception {}$a = new Exception('hi'); // $a 是类 A\B\C\Exception 的一个对象$b = new \Exception('hi'); // $b 是类 Exception 的一个对象$c = new ArrayObject; // 致命错误, 找不到 A\B\C\ArrayObject 类
<?phpnamespace A\B\C;const E_ERROR = 45;function strlen($str){ return \strlen($str) - 1; }echo E_ERROR, "\n"; // 输出 "45"echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALLecho strlen('hi'), "\n"; // 输出 "1"if (is_array('hi')) { // 输出 "is not array" echo "is array\n"; } else { echo "is not array\n"; }
对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。
所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。
在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。
在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:
在当前命名空间中查找名为 A\B\foo() 的函数
尝试查找并调用 全局(global) 空间中的函数 foo()。
在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: new C()的解析:
new D\E()的解析:
为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。
在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
尝试自动装载类 A\B\D\E。
在当前命名空间中查找A\B\C类。
尝试自动装载类A\B\C。
<?phpnamespace 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"?>
相关推荐:
Atas ialah kandungan terperinci 完全掌握php命名空间. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!