How to Use PHP Namespaces, Part 1: The Basics

命名空间是一个重要的概念。该系列文章详细介绍了PHP对命名空间的支持及用法。原文地址:http://www.sitepoint.com/php-53-namespaces-basics/

命名空间是PHP 5.3诸多重要更新中的一个。它会使C#和Java开发者感到友好,同时很有希望使PHP应用的程序结构变得更好。

为什么需要命名空间?

随着你的PHP代码库的增长,意外重定义之前已声明过的函数的风险也在增加。这个问题会在引入第三方组件或插件时恶化——如果多段代码都实现了”Database”或者”User”类, 会发生什么呢?

直到现在,唯一的解决方案就是命名一个较长的类或函数名。例如,WordPress在每一个命名前使用”WP_”前缀。Zend Framework使用高度可描述的命名约定,而这会导致产生诸如Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive这样冗长的类名。

命名空间可解决命名冲突的问题。可以把PHP常量、类和函数组织到使用了命名空间的代码库中。

如何定义命名空间?

默认情况下,所有的常量、类及函数命名都位于全局空间内——就像PHP未支持命名空间之前的样子。

命名空间化的代码在PHP文件的顶部使用namespace关键字。该关键字之前不能有PHP或HTML代码,只可有空白字符或declare关键字。


1

2

3

4

<?php

// define this code in the ‘MyProject‘ namespace

namespace MyProject;

// ... code ...

  在namespace关键字之后的代码都会纳入”MyProject”命名空间。命名空间不能嵌套或在同一代码处声明多次(只有最后一次会被识别)。但是,你能在同一个文件中定义多个命名空间化的代码。


1

2

3

4

5

6

7

8

9

10

<?php

namespace MyProject1;

// PHP code for the MyProject1 namespace

namespace MyProject2;

// PHP code for the MyProject2 namespace

// Alternative syntax

namespace MyProject3 {

    // PHP code for the MyProject3 namespace

}

?>

虽然这种用法从语法方面讲是可行的,但明智的做法是每个文件定义一个命名空间。

  子命名空间

PHP允许定义命名空间层级。子命名空间使用反斜线来分隔。例如:

  • MyProject\SubName
  • MyProject\Database\MySQL
  • CompanyName\MyProject\Library\Common\Widget1

调用已命名空间化的代码

在lib1.php文件中的App\Lib1命名空间内定义一个常量、一个函数以及一个类

  lib1.php


1

2

3

4

5

6

7

8

9

10

11

12

13

<?php

// application library 1

namespace App\Lib1;

const MYCONST = ‘App\Lib1\MYCONST‘;

function MyFunction() {

     return __FUNCTION__;

}

class MyClass {

     static function WhoAmI() {

          return __METHOD__;

     }

}

?>

在另一个PHP文件中包含此文件。

  myapp.php


1

2

3

4

5

6

7

<?php

header(‘Content-type: text/plain‘);

require_once(‘lib1.php‘);

echo \App\Lib1\MYCONST . "\n";

echo \App\Lib1\MyFunction() . "\n";

echo \App\Lib1\MyClass::WhoAmI() . "\n";

?>

因在myapp.php中未定义任何命名空间,所以全部代码都位于全局空间内。任何对MYCONST、MyFunction 或者MyClass 的直接引用都会失败,因为他们位于App\Lib1命名空间内。当想调用lib1.php中的代码,必须加上”\App\Lib1″前缀形成完全限定名(fully-qualified names)。myapp.php的运行结果为:

App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI

完全限定名也会很长,而且相对于诸如 App-Lib1-MyClass这样的长类名并无明显好处。因此,在下篇文章中将会讨论命名空间别名,同时对PHP如何处理命名空间做近距离观察。

How to Use PHP Namespaces, Part 2: Importing, Aliases, and Name Resolution

在下面的示例中,定义了两段几乎完全相同的代码,唯一的不同之处就在于它们的命名空间。

lib1.php


1

2

3

4

5

6

7

8

9

10

11

12

13

<?php

// application library 1

namespace App\Lib1;

const MYCONST = ‘App\Lib1\MYCONST‘;

function MyFunction() {

    return __FUNCTION__;

}

class MyClass {

    static function WhoAmI() {

        return __METHOD__;

    }

}

?>

lib2.php


1

2

3

4

5

6

7

8

9

10

11

12

13

<?php

// application library 2

namespace App\Lib2;

const MYCONST = ‘App\Lib2\MYCONST‘;

function MyFunction() {

    return __FUNCTION__;

}

class MyClass {

    static function WhoAmI() {

        return __METHOD__;

    }

}

?>

先来了解一些PHP术语:
完全限定名
任何PHP代码都具有完全限定名——一个以反斜线起始的标识符。例如:\App\Lib1\MYCONST, \App\Lib2\MyFunction()。
完全限定名不会产生任何歧义。首个反斜线与文件系统路径类似,都指明了“根”全局空间。如果在全局空间内实现了一个MyFunction()函数,可在lib1.php和lib2.php中使用“\MyFunction()”对其进行调用。
完全限定名对一次性函数调用或对象初始化有帮助。然而,它们不适用于大量调用的情况。就像接下来要看到的,PHP为命名空间输入提供了其他一些选择。
部分限定名
至少有一个命名空间分隔符的标识符。例如:Lib1\MyFunction().
未限定名
没有命名空间分隔符的标识符。例如:MyFunction().

在同一命名空间内工作
考虑以下代码:
myapp1.php


1

2

3

4

5

6

7

8

9

<?php

namespace App\Lib1;

require_once(‘lib1.php‘);

require_once(‘lib2.php‘);

header(‘Content-type: text/plain‘);

echo MYCONST . "\n";

echo MyFunction() . "\n";

echo MyClass::WhoAmI() . "\n";

?>

虽然同时包含了lib1.php和lib2.php,但MYCONST, MyFunction, and MyClass只会引用lib1.php中的代码。因为myapp1.php的代码同样位于App\lib1命名空间内。
result:
App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI

命名空间导入
命名空间可通过use操作符导入。例如
myapp2.php

1

2

3

4

5

6

7

8

9

<?php

use App\Lib2;

require_once(‘lib1.php‘);

require_once(‘lib2.php‘);

header(‘Content-type: text/plain‘);

echo Lib2\MYCONST . "\n";

echo Lib2\MyFunction() . "\n";

echo Lib2\MyClass::WhoAmI() . "\n";

?>

可使用任意数量的use语句或使用逗号分隔每个独立的命名空间。在此例中,导入了“App\Lib2”命名空间。但此刻仍然无法直接引用MYCONST, MyFunction 或 MyClass,因为调用他们的代码位于全局空间内,PHP将会在全局空间内查找它们。然而,如果我们加入“Lib2\”前缀,它们便形成部分限定名,PHP将会在已导入的命名空间内搜索直到找到匹配项。

result

App\Lib2\MYCONST
App\Lib2\MyFunction
App\Lib2\MyClass::WhoAmI

命名空间别名

命名空间别名或许是最有帮助的功能。别名可使较短的名称来代替较长名称。

myapp3.php


1

2

3

4

5

6

7

8

9

10

11

<?php

use App\Lib1 as L;

use App\Lib2\MyClass as Obj;

header(‘Content-type: text/plain‘);

require_once(‘lib1.php‘);

require_once(‘lib2.php‘);

echo L\MYCONST . "\n";

echo L\MyFunction() . "\n";

echo L\MyClass::WhoAmI() . "\n";

echo Obj::WhoAmI() . "\n";

?>

第一个use语句设定"App/Lib1"的别名为“L”,任何使用"L"的部分限定名都会在编译阶段被解释为“App/Lib1”。因此可使用 L\MYCONST 和 L\MyFunction来代替完全限定名。

第二个use语句非常有趣。它将‘Obj‘设定为App\Lib2命名空间内的类MyClass的别名。这种别名设定方式只对类有效,常量与函数不适用。

设定类别名后,就可以用new Obj()来创建实例或直接调用静态方法了。

App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI
App\Lib2\MyClass::WhoAmI

PHP命名解析规则
PHP标识符命名解析遵循以下规则:
1. 在编译阶段解析拥有完全限定名的常量、类或函数的调用。
2. 未限定和部分限定名根据命名空间导入规则进行解释。例如,如果命名空间A\B\C被导入且设定别名为C,那么C\D\e()调用将被解释为A\B\C\D\e()
3. 在命名空间内,所有未根据命名空间导入规则进行解释的部分限定名都会拥有当前命名空间的前缀。例如:如果在命名空间A\B内执行C\D\e()调用,它将会被解释为 A\B\C\D\e()。

4. 未限定的类名会根据当前导入的命名空间进行解释,同时会使用全名来代替缩写后的名称。例如:如果在命名空间A\B内的类C被导入为X,new X()将被解释为 new A\B\C()。
5. 命名空间内的未限定函数调用会在运行时解析。例如:如果MyFunction()在命名空间A\B内被调用,PHP首先会搜索函数\A\B\MyFunction(),如果未找到匹配项,PHP会在全局空间内搜索\MyFunction()函数。
6. 调用未限定或部分限定名的类会在运行时解析。例如:如果在命名空间A\B内调用new C(),PHP会搜索类A\B\C,如果未能找到匹配项,PHP将会试图自动载入类A\B\C。

时间: 2024-12-08 10:28:39

How to Use PHP Namespaces, Part 1: The Basics的相关文章

.NET Framework posters with Namespaces &amp; Types

Framework is platform containing a huge library of types, methods, classes, etc., cataloged into namespaces. But it is not ending here. With each new version of the framework, a new bunch of features is added to already existing ones. So, it is getti

[单元测试]VS-通过代码添加单元测试提示No classes or namespaces in this assembly

在Visual Studio 2012中,打算给以下方法添加单元测试,但却出现了提示:No classes or namespaces in this assembly的提示. 1 namespace UnitTest 2 { 3 class Program 4 { 5 public int Add(int a, int b) 6 { 7 return a + b; 8 } 9 public int Divide(int a, int b) 10 { 11 return a / b; 12 }

Namespaces

Namespaces are heavily used in C# programming in two ways. First, the .NET Framework uses namespaces to organize its many classes, as follows:System.Console.WriteLine("Hello World!"); System  is a namespace and Console is a class in that namespa

[Quote] 3.6 Namespaces

From http://www.informit.com/articles/article.aspx?p=31783&seqNum=6 This chapter is from the book Navigating C++ and Object-Oriented Design (Bk/CD-ROM) 3.6 Namespaces An earlier section ("Storage Classes" on page 124) explains scope rules fo

Python Scopes and Namespaces

Before introducing classes, I first have to tell you something about Python's scope rules. Class definitions play some neat tricks with namespaces, and you need to know how scopes and namespaces work to fully understand what's going on. Incidentally,

Linux network namespaces

介绍OpenStack neutron使用Linux网络命名空间来避免物理网络和虚拟网络间的冲突,或者不同虚拟网络间的冲突. 网络命名空间就是一个独立的网络协议栈,它有自己的网络接口,路由,以及防火墙规则. 网络命名空间通常是位于目录/var/run/netns/下的文件描述符. 例如,使用ip netns add命令创建一个命名空间: ip netns add bule 查看目录/var/run/netns/: $ ls /var/run/netns/ blue 网络命名空间常用于虚拟化中.因

Linux Namespaces机制

Linux Namespaces机制提供一种资源隔离方案.PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace.每个Namespace里面的资源对其他Namespace都是透明的.要创建新的Namespace,只需要在调用clone时指定相应的flag.Linux Namespaces机制为实现基于容器的虚拟化技术提供了很好的基础,LXC(Linux containers)就是利用这一特性实现了资源的隔离.不同container内的进程属于不同的Namespa

XML 命名空间(XML Namespaces)

XML 命名空间提供避免元素命名冲突的方法. 命名冲突 在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突. 这个 XML 文档携带着某个表格中的信息: <table> <tr> <td>Apples</td> <td>Bananas</td> </tr> </table> 这个 XML 文档携带有关桌子的信息(一件家具): <table> <nam

NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.

解决办法: http://stackoverflow.com/questions/4037125/namespace-err-an-attempt-is-made-to-create-or-change-an-object-in-a-way-which-i http://docs.spring.io/spring-ws/site/faq.html#namespace_err I get NAMESPACE_ERR exceptions when using Spring-WS. What can