PHP namespace介绍与使用

命名空间概述


什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件 foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到 /home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念。


在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题

  1.     1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突

  2.     2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性


定义命名空间


一个文件中如果包含了命名空间,他必须在所有代码之前申明命名空间,除了declare关键字,否则的话,会报Fatal error级别错误,在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。

echo 'hello world';
namespace myProject;

会提示Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in。


使用命名空间


在讨论如何使用命名空间之前,必须了解 PHP 是如何知道要使用哪一个命名空间中的元素的。可以将 PHP 命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:

  1.     1.     相对文件名形式如foo.txt。它会被解析为 currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是 /home/foo,则该文件名被解析为/home/foo/foo.txt 
  2.     2.     相对路径名形式如subdirectory/foo.txt。它会被解析为 currentdirectory/subdirectory/foo.txt
  3.     3.    绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt

PHP 命名空间中的元素使用同样的原理。例如,类名可以通过三种方式引用  
  1.     1.     非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称 。
  2.     2.    限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo
  3.     3.    完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或\currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo


下面我们用例子说明下:

file1.php

namespace Foo\Bar\subnamespace;

const FOO = 1;

function foo() {
    echo 'file1.php文件中的foo函数'.'
';
}

class foo { static function staticmethod() { echo 'file1.php文件中的foo类'.'
'; } }

file2.php

namespace Foo\Bar;
include 'file1.php';

const FOO = 2;

function foo() {     echo 'file2.php文件中的foo函数'.'
'; }

class foo { static function staticmethod() { echo 'file2.php文件中的foo类'.'
'; } }

我们先通过非限定名称来访问下file2.php,表示当前Foo\Bar空间

foo();               // 解析为Foo\Bar\foo()函数
foo::staticmethod(); //解析为类 Foo\Bar\foo的静态方法staticmethod
echo FOO;

结果分别为:

file2.php文件中的foo函数

file2.php文件中的foo类

2


细心的小伙伴可能会有疑问:为什么引入了file1.php,但是结果并不是file1.php中的结果呢,其实我以前也犯过这样的错误,以为include和require会覆盖上面的代码,其实不然,因为在一个类中导入了另一个类之后,当前的命名空间仍然是当前类的命名空间,所以结果自然是file2.php中的结果,这边涉及到非限定名称的问题。


所谓非限定名称就是标识函数,常量,变量,类这些不带任何前缀标识,就像我和你是同一个班级,我想找你,直呼其名就行,可以不用具体到某部门某班级,因为我们所处同一空间域。但是如果别的部门的同学要找你,就需要指明某个部门的某个班级的某某某学生才能精确找到你这个人,这边就又涉及到限定名称的概念。

下面就以限定名称的方式来访问file2.php,表示相对于Foo\Bar空间

subnamespace\foo();               //解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类Foo\Bar\subnamespace\foo,以及类的方法 staticmethod
echo subnamespace\FOO;            //解析为常量 Foo\Bar\subnamespace\FOO

结果分别为:

file1.php文件中的foo函数

file1.php文件中的foo类
1  

这边也好理解,从file2.php中去找file1.php中的数据


最后一种以完全限定名称的方式来访问file2.php,表示绝对于Foo\Bar空间

\Foo\Bar\foo()                //解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO;            // 解析为常量 Foo\Bar\FOO

结果分别为: 

 file2.php文件中的foo函数

file2.php文件中的foo类

2


上面的三个例子其实可以把类比为文件名(例如 foo.php)、相对路径名(例如 ./subnamespace/foo  )、绝对路径名(例如 /Foo/Bar/subnamespace/foo  ),这样可能会更容易理解。  


至此,php的命名空间的定义与使用已介绍完,如有错误,欢迎指正。下节将介绍命名空间的别名导入部分[微笑]

上一篇: Ubuntu/Debian下配置Shadowsocks访问外网

下一篇: 没有了

分享

版权属于:破冰者博客

文章链接:https://ice-breaker.cn/post/24

转载时必须以链接形式注明原始出处及本声明。

表情