多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] * * * * * ## 1 命名空间的意义(参考php官方手册编写) >[info] 1 命名空间的作用 声明php中类名,函数名,常量名这三类符号命名范围 >[info] 2 命名空间的引入 在**php5.3引入命名空间之前**,上述三类符号的命名范围是**全局空间**,在大型工程项目中,容易出现**符号命名重复冲突**。 为了解决大型工程项目的符号命名冲突问题,在**php5.3中引入命名空间**的支持。 **因此命名空间是用来声明类名,函数名,常量名三类符号命名范围** >[info] 3 其他符号名作用范围分析 **预定义变量**的作用范围 在全局空间。通常前置$_符号 `$GLOBALS $_SERVER $_GET` **普通变量**的作用范围 在当前大括号限制的局部空间中。通常前置$符号 ~~~ if(){} while(){} funciont(){} class xx{} ~~~ * * * * * ## 2 命名空间的简单使用 >[info] 1 命名空间的声明 **关键字 namespae test;** 声明当前命名空间为test,限制其后三类符号的作用域 * * * * * example1: 命名空间的声明方法 ~~~ <?php namespace MyProject ; const CONNECT_OK = 1 ; class Connection { /* ... */ } function connect () { /* ... */ } ?> ~~~ * * * * * 需要注意的是namespace 必须在当前文件的第一行。 example2: 命名空间的错误使用 ~~~ <html> <?php namespace MyProject ; // 致命错误 - 命名空间必须是程序脚本的第一条语句 ?> ~~~ >[info] 2 命名空间的符号使用 **`__NAMESPACE__ ` 当前命名空间名称** example3: `__NAMESPACE__ `命名空间中使用 ~~~ <?php namespace MyProject ; echo '"' , __NAMESPACE__ , '"' ; // 输出 "MyProject" ?> ~~~ * * * * * 不包含命名空间的的全局空间输出空字符串 example4:`__NAMESPACE__ `非命名空间中使用 ~~~ <?php echo '"' , __NAMESPACE__ , '"' ; // 输出 "" ?> ~~~ * * * * * **namespace 当前命名空间名称使用,相当于self操作符** example5:命名空间中namespae的使用 ~~~ <?php namespace MyProject ; // 调用函数 MyProject\blah\mine() namespace\ blah \ mine (); // 调用函数 MyProject\func() namespace\ func (); // 调用函数 MyProject\sub\func() namespace\ sub \ func (); // 调用MyProject\cname类的静态方法method namespace\ cname :: method (); // 实例化MyProject\sub\cname类的对象 $a = new namespace\ sub \ cname (); // 将常量MyProject\CONSTANT赋值给$b $b = namespace\ CONSTANT ; ?> ~~~ * * * * * 不包含命名空间的全局空间,使用全局符号名 example6: 非命名空间中namespace的使用 ~~~ <?php namespace\ func (); // 调用函数 func() namespace\ sub \ func (); // 调用函数 sub\func() namespace\ cname :: method (); // 调用类cname的静态方法method $a = new namespace\ sub \ cname (); // 实例化类sub\cname对象 $b = namespace\ CONSTANT ; // 将常量CONSTANT赋值给$b ?> ~~~ >[info] 3 类名的引用 **1-1不带前缀:非命名空间** ~~~ <?php $a=new foo(); foo::staticmethod();。 ?> ~~~ foo 将被解析为 foo * * * * * **1-2不带前缀:带有命名空间** ~~~ <?php namespace currentnamespace; $a=new foo(); foo::staticmethod();。 ?> ~~~ foo 将被解析为 currentnamespace\foo * * * * * **2-1非反斜杠开头的前缀:不带命名空间** ~~~ <?php $a = new subnamespace\foo(); subnamespace\foo::staticmethod(); ?> ~~~ foo 会被解析为subnamespace\foo * * * * * **2-2非反斜杠开头的前缀:带命名空间** ~~~ <?php namespace currentnamespace $a = new subnamespace\foo(); subnamespace\foo::staticmethod(); ?> ~~~ foo 会被解析为 currentnamespace\subnamespace\foo **3 以反斜杠开头的前缀:命名空间或非命名空间中** ~~~ <?php $a = new \currentnamespace\foo(); \currentnamespace\foo::staticmethod(); ?> ~~~ foo 总是被解析为全局符号currentnamespace\foo。 >[info] 4 函数与常量名的引用 如果当前命名空间不存在。会使用全局空间中的函数和常量名称 ~~~ <?php namespace 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_ALL echo strlen ( 'hi' ), "\n" ; // 输出 "1" if ( is_array ( 'hi' )) { echo "is array\n" ; } else { echo "is not array\n" ; } // 输出 "is not array" ?> ~~~ >[info] 5 非命名空间与命名空间的元素 非命名空间元素到命名空间元素必须使用完全限定名称,**前面需要使用反斜杠** 如果使用**变量表示(动态)**的类名,函数名或常量名, 限定名称和完全限定名称没有区别,因此**其前导的反斜杠是不必要的**。 example7:命名空间限定 ~~~ example7_1.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 ?> ~~~ ~~~ example7_2.php: <?php namespace namespacename ; class classname { function __construct () { echo __METHOD__ , "\n" ; } } function funcname () { echo __FUNCTION__ , "\n" ; } const constname = "namespaced" ; include 'example7_1.php' ; $a = 'classname' ; $obj = new $a ; // 输出 classname::__construct $b = 'funcname' ; $b (); // 输出 funcname echo constant ( 'constname' ), "\n" ; // 输出 global ~~~ ~~~ /* 双引号会对反斜杠\进行转义,因此需要使用 "\\namespacename\\classname" 表示命名空间的限定 */ $a = '\namespacename\classname' ; $obj = new $a ; // 输出 namespacename\classname::__construct $a = 'namespacename\classname' ; $obj = new $a ; // 输出 namespacename\classname::__construct $b = 'namespacename\funcname' ; $b (); // 输出 namespacename\funcname $b = '\namespacename\funcname' ; $b (); // 输出 namespacename\funcname echo constant ( '\namespacename\constname' ), "\n" ; // 输出 namespaced echo constant ( 'namespacename\constname' ), "\n" ; // 输出 namespaced ?> ~~~ >[info] 6 全局空间 如果没有定义命名空间,所有的类与函数定义在全局空间。 名称前加上前缀\表示该名称是全局命名空间中的名称。 example8: ~~~ <?php namespace A \ B \ C ; /* 这个函数是 A\B\C\fopen */ function fopen () { // 调用全局的fopen函数 $f = \fopen (...); return $f ; } ?> ~~~ ## 3 命名空间的别名与导入 **关键字use test** 可以用来定义命名空间与类的别名 * * * * * example8:使用use操作符导入/使用命名空间与类别名. ~~~ <?php namespace foo ; use My\Full\Classname as Another ; // 等价于 use My\Full\NSname as NSname use My\Full\NSname ; // 导入一个全局类 use \ArrayObject ; $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 对象 ?> ~~~ * * * * * example9: 通过use操作符导入/使用别名, 一行中包含多个use语句 ~~~ <?php use My \ Full \ Classname as Another , My \ Full \ NSname ; $obj = new Another ; // 实例化 My\Full\Classname 对象 NSname \ subns \ func (); // 调用函数 My\Full\NSname\subns\func ?> ~~~ * * * * * >[danger] 1 函数与常量不可以使用use定义别名 >[danger] 2 导入操作是在编译时执行的。 使用变量表示(动态)的类名,函数名称或常量名称则是运行时执行的 ~~~ <?php use My \ Full \ Classname as Another , My \ Full \ NSname ; $obj = new Another ; // 实例化一个 My\Full\Classname 对象 $a = 'Another' ; $obj = new $a ; // 实际化一个 Another 对象 ?> ~~~ >[danger] 3 导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。 example10 导入完全限定名称 ~~~ <?php use My \Full\Classname as Another , My\Full\NSname ; $obj = new Another ; // 实例化My\Full\Classname的对象 $obj = new \Another ; // 实例化Another类的对象 $obj = new Another\thing ; // 实例化类My\Full\Classname\thing的对象 $obj = new \Another \ thing ; // 实例化类Another\thing的对象 ?> ~~~ ## 4 名称解析规则总结 >[info] 1 命名空间名称定义 非限定名称Unqualified name 名称中不包含命名空间分隔符的标识符,例如 Foo 限定名称Qualified name 名称中含有命名空间分隔符的标识符,例如 Foo\Bar 完全限定名称Fully qualified name 名称中包含命名空间分隔符,并以命名空间分隔符开始的标识符, 例如 \Foo\Bar。 namespace\Foo 也是一个完全限定名称。 >[info] 2 名称解析遵循下列规则: 1. 对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。 2. 所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。 3. 在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。 4. 非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。 5. 在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的: 1. 在当前命名空间中查找名为 A\B\foo() 的函数 2. 尝试查找并调用 全局(global) 空间中的函数 foo()。 6. 在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: new C()的解析: 1. 在当前命名空间中查找A\B\C类。 2. 尝试自动装载类A\B\C。 new D\E()的解析: 1. 在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。 2. 尝试自动装载类 A\B\D\E。 为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。 >[info] 3 示例 example 11 名称解析规则 ~~~ <?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" ?> ~~~ ## 5 总结 >[info] 1 命名空间的意义 声明类,函数,常量名的命名空间,防止命名冲突。 >[info] 2 命名空间的简单使用 命名空间中符号名称的使用方法 >[info] 3 命名空间的别名与导入 命名空间中类的别名使用方法 >[info] 4 命名空间名称解析规则 根据前缀解析