技术开发 频道

PHP V5.3 中的新特性: 名称空间

  【IT168 技术文章】很多语言都提供了名称空间特性,包括 C++ 和 Java™ 编程语言。引入名称空间是为了帮助组织大型的代码库,因为在大型代码库中,应用程序经常会出现函数名或类名重叠问题,这会引起其他问题。使用名称空间可以帮助识别代码提供的函数或实用程序,甚至可以帮助指定其来源。一个例子就是 C# 中的 System 名称空间,它包含有 .NET 框架提供的所有函数和类。

  在其他未提供正式名称空间的语言中(比如 PHP V5.2 以及更早版本),人们常常通过在类或函数名中使用特定的命名约定来发挥名称空间的作用。比如 Zend Framework,其中每个类名以 Zend 开头,并且每个子名称空间使用下划线分隔开。比如,类定义 Zend_Db_Table 表示 Zend Framework 中的一个类并且提供数据库功能。这种方法的一个缺点就是产生的代码非常繁琐,尤其是那些包含好几层的类或函数(Zend Framework 中的 Zend_Cache_Backend_Apc 就是一个例子)。另一个问题就是所有代码必须遵循这种风格,因此如果在应用程序中集成了不遵循这种命名约定的第三方代码后,问题就复杂了。

  PHP 名称空间的发展也并非一帆风顺。它们最初计划引入到 PHP V5 中,但是由于无法获得恰当的实现,因此在开发阶段被放弃。最后决定将它们并入到 PHP V6 中,在 2007 年决定将所有 nonunicode 增强移到另一个 PHP V5.x 发行版后,名称空间随后被移入到 PHP V5.3 中。尽管自最初的设计之后绝大部分名称空间行为没有发生变化,但是使用哪一种操作符却成了最大的问题,并且社区成员对这个问题有不同的看法。2008 年 10 月最终决定使用反斜杠作为操作符,从而解决了所有在语言设计和适用性方面使用各种其他操作符的问题。

  PHP 名称空间

  PHP 从其他语言中借鉴了很多名称空间的语法和设计 — 最突出的是 C++。然而,PHP 名称空间在某些方面具有自己的独特性,这对于希望像在其他语言中那样使用名称空间的用户来说是一个挑战。在本节中,我们将研究 PHP 名称空间的工作方式。

  定义一个名称空间

  定义一个新的名称空间非常简单。要定义新名称空间,在一个文件中添加清单 1 中的代码作为第一个命令或输出。

  清单 1. 定义名称空间

1 <?php
2 namespace Foo;
3 class Example {}
4 ?>
5

  注意,以上 namespace 的声明必须是文件中的第一个命令或输出。在它的前面添加任何内容都会导致一个致命的错误。清单 2 展示了有关这方面的一些例子。

  清单 2. 定义名称空间的错误方法

1 /* File1.php */
2 <?php
3 echo "hello world!";
4 namespace Bad;
5 class NotGood {}
6 ?>
7
8 /* File2.php */
9 <?php
10 namespace Bad;
11 class NotGood {}
12 ?>
13

  在清单 2 的第 1 部分中,我们尝试在名称空间定义之前回传到控制台,这导致产生一个致命错误。在清单的第 2 部分中,我们在

  但是,上面的两个例子都可以重新编写,将名称空间定义和将在名称空间声明中放入的代码放到独立的文件中,然后再将此文件包含到原始文件中。清单 3 演示了这一点。

  清单 3. 修正定义名称空间的错误方法

1 /* Good.php */
2 <?php
3 namespace Good;
4 class IsGood() {}
5 ?>
6
7 /* File1.php */
8 <?php
9 echo "hello world!";
10 include './good.php';
11 ?>
12
13 /* File2.php */
14 <?php
15 include './good.php';
16 ?>
17

  现在我们已经了解了如何在一个文件中定义代码的名称空间,接下来让我们看看如何在应用程序中利用这个使用名称空间的代码。

  使用带有名称空间的代码

  定义了名称空间并在其中放入代码后,我们就可以在应用程序中方便地使用它。可以使用很多种方法调用带有名称空间的函数、类或常量。一种方式是显式地将名称空间引用为调用的前缀。另一种方法是为名称空间定义一个别名并使用该别名作为调用的前缀,这样做的目的是简化名称空间前缀。最后,我们可以只在代码中使用名称空间,这就使它成为默认名称空间,并且在默认情况下,使所有代码都引用默认名称空间。清单 4 演示了调用之间的不同之处。

  清单 4. 在名称空间内调用函数

1 /* Foo.php */
2 <?php
3 namespace Foo;
4 function bar()
5 {
6     echo "calling bar....";
7 }
8 ?>
9
10 /* File1.php */
11 <?php
12 include './Foo.php';
13 Foo/bar(); // outputs "calling bar....";
14 ?>
15
16 /* File2.php */
17 <?php
18 include './Foo.php';
19 use Foo as ns;
20 ns/bar(); // outputs "calling bar....";
21 ?>
22
23 /* File3.php */
24 <?php
25 include './Foo.php';
26 use Foo;
27 bar(); // outputs "calling bar....";
28 ?>
29

  清单 4 演示了在名称空间 Foo 内调用函数 bar() 的不同方法。在 File1.php 内,我们看到了如何进行显式调用,使用名称空间的名称作为调用前缀。File2.php 使用名称空间名称的别名,因此我们使用别名代替名称空间的名称。最后,File3.php 仅使用名称空间,这允许我们不需要使用任何前缀来调用 bar()。

  我们还可以在一个文件内定义多个名称空间,只需要在文件中添加更多 namespace 调用。清单 5 演示了这一点。

  清单 5. 文件中的多个名称空间

1 <?php
2 namespace Foo;
3 class Test {}
4
5 namespace Bar;
6 class Test {}
7
8 $a = new Foo\Test;
9 $b = new Bar\Test;
10
11 var_dump($a, $b);
12
13 Output:
14 object(Foo\Test)#1 (0) {  
15 }  
16 object(Bar\Test)#2 (0) {  
17 }
18

  现在我们已经基本了解了如何在名称空间内进行调用,让我们了解一些更复杂的名称空间调用以及它们如何工作。

0
相关文章