笔记008 PHP的命名空间 - 中篇
使用命名空间:基础
PHP判断使用哪个命名空间中元素发方法
在这里,可以将 PHP 命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:
相对文件名形式如foo.txt。它会被解析为 currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是 /home/foo,则该文件名被解析为/home/foo/foo.txt。
相对路径名形式如subdirectory/foo.txt。它会被解析为 currentdirectory/subdirectory/foo.txt。
绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。
PHP命名空间使用了相同的原理。例如,类名通过以下三种方式均可正常引用:
非限定名称,或不包含前缀的类名称,例如 $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。
动态类中的命名空间要点
example1.php
<?phpclass 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 funcnameecho constant('constname'), "\n"; // prints global?>
如果要将下面的代码转换到命名空间中,必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。
<?phpnamespace namespacename;class classname{ function __construct() { echo __METHOD__,"\n"; } }function funcname(){ echo __FUNCTION__,"\n"; }const constname = "namespaced";include 'example1.php'; $a = 'classname'; $obj = new $a; // 输出 classname::__construct$b = 'funcname'; $b(); // 输出 funcnameecho constant('constname'), "\n"; // 输出 global /* 注意: 如果使用的双引号,则必须采用 "\\namespacename\\classname" 的形式,这是因为字符串转义的原因,不明白的请参考PHP转义 */ $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\funcnameecho constant('\namespacename\constname'), "\n"; // 输出 namespacedecho constant('namespacename\constname'), "\n"; // 依然输出 namespaced?>
namespace关键字和NAMESPACE常量
PHP支持两种抽象的访问当前命名空间内部元素的方法,NAMESPACE 魔术常量和namespace关键字。注意:魔术常量是两个下划线
NAMESPACE
常量NAMESPACE的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
<?php namespace MyProject; echo '"', __NAMESPACE__, '"'; // 输出 "MyProject" ?>
全局代码,即没有命名空间的时候,输出空字符串。
常量 NAMESPACE 在动态创建名称时很有用,例如:
<?phpnamespace MyProject;function get($classname){ $a = __NAMESPACE__ . '\\' . $classname; return new $a; }?>
namespace
关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中的 self 操作符。
<?php namespace MyProject; use blah\blah as mine; // see "Using namespaces: importing/aliasing" blah\mine(); // calls function blah\blah\mine() namespace\blah\mine(); // calls function MyProject\blah\mine() namespace\func(); // calls function MyProject\func() namespace\sub\func(); // calls function MyProject\sub\func() namespace\cname::method(); // calls static method "method" of class MyProject\cname $a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname $b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b ?>
使用命名空间中的别名/导入
允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中可以创建对其它的文件或目录的符号连接。
所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。
在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的五种导入方式的例子:
<?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\functionNameecho CONSTANT; // echoes the value of My\Full\CONSTANT?>
注意对命名空间中的名称(包含命名空间分隔符的完全限定名称如 Foo\Bar以及相对的不包含命名空间分隔符的全局名称如 FooBar)来说,前导的反斜杠是不必要的也不推荐的,因为导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析。
为了简化操作,PHP还支持在一行中使用多个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 对象?>
另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
<?php use 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 ?>
解析优先策略
在一个命名空间中,当 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 类?>
函数和常量的解析优先级
对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
<?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_ALL echo strlen('hi'), "\n"; // 输出 "1" if (is_array('hi')) { // 输出 "is not array" echo "is array\n"; } else { echo "is not array\n"; }?>
以上就是笔记008 PHP的命名空间 - 中篇的内容,更多相关内容请关注PHP中文网(www.php.cn)!