分类: 系统运维
2011-07-04 14:12:05
为什么我们需要命名空间?
随着你的PHP代码库的增长,对之前定义的函数和类名进行修改时风险也更高了,当你试图增加第三方组件或插件时问题更严重,如果存在两个或两个以上的代码集实现了一个“Database”和“User”类会怎么样?
直到目前,唯一的解决办法是使用长的类/函数名,例如Wordpress在每个类和函数名前都使用了前缀“WP_”, Zend Framework使用了极具描述性的命名约定,导致类名非常冗长,如:
Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive
命名冲突问题可以使用命名空间来解决,PHP常量、类和函数可以被组合到命名空间库中。
如何定义命名空间?
默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。
在PHP文件的顶部使用一个关键字namespace就可以定义命名空间,它必须是第一个命令(declare除外),在它前面不能出现非PHP代码、HTML或空格。如:
这一行下面的代码都是指定给MyProject命名空间的,为相同代码块嵌套命名空间或定义多个命名空间是不可能的,如果你真这样干,只有最后一个命名空间才能识别,但你可以在同一个文件中定义不同的命名空间代码,如:
尽管这么干是可以的,但我建议你不要这么做,最好还是每个文件中只定义一个命名空间,免得把你弄糊涂了。
子命名空间
PHP允许定义具有层次的命名空间以便库能够细分,子命名空间使用一个反斜线字符(\)分隔,如:
◆MyProject\SubName
◆MyProject\Database\MySQL
◆CompanyName\MyProject\Library\Common\Widget1
调用命名空间代码
在lib1.php文件中我们使用App\Lib1 namespace命名空间定义了一个常量、一个函数和一个类,如:
lib1.php
现在我们可以在另一个PHP文件包括这段代码,如:
myapp.php
在myapp.php中并没有定义命名空间,因此这段代码存在全局空间中,任何对MYCONST、MyFunction和MyClass的直接引用 都会失败,因为它们存在于App\Lib1命名空间中,为了调用lib1.php中的代码,我们可以在\App\Lib1命名空间前添加前缀定义一个完全 合格的名称,下面是我载入myapp.php时的输出结果:
完全合格名称可以变得很长,定义长名称,如App-Lib1-MyClass,有一些明显的好处。
清单 1. 定义名称空间
php namespace Foo; class Example {} ?> |
/* File1.php */ php echo "hello world!"; namespace Bad; class NotGood {} ?> /* File2.php */ php namespace Bad; class NotGood {} ?> |
/* Good.php */ php namespace Good; class IsGood() {} ?> /* File1.php */ php echo "hello world!"; include './good.php'; ?> /* File2.php */ php include './good.php'; ?> |
/* Foo.php */ php namespace Foo; function bar() { echo "calling bar...."; } ?> /* File1.php */ php include './Foo.php'; Foo/bar(); // outputs "calling bar...."; ?> /* File2.php */ php include './Foo.php'; use Foo as ns; ns/bar(); // outputs "calling bar...."; ?> /* File3.php */ php include './Foo.php'; use Foo; bar(); // outputs "calling bar...."; ?> |
php namespace Foo; class Test {} namespace Bar; class Test {} $a = new Foo\Test; $b = new Bar\Test; var_dump($a, $b); Output: object(Foo\Test)#1 (0) { } object(Bar\Test)#2 (0) { } |
/* global.php */ php function hello() { echo 'hello from the global scope!'; } ?> /* Foo.php */ php namespace Foo; function hello() { echo 'hello from the Foo namespace!'; } ?> /* Foo_Bar.php */ php namespace Foo/Bar; function hello() { echo 'hello from the Foo/Bar namespace!'; } ?> |
php include './global.php'; include './Foo.php'; include './Foo_Bar.php'; use Foo; hello(); // outputs 'hello from the Foo namespace!' Bar\hello(); // outputs 'hello from the Foo/Bar namespace!' \hello(); // outputs 'hello from the global scope!' ?> |
php require_once('PEAR/Date.php'); use PEAR\Date; // the name of the namespace we've specified in PEAR/Date.php // since the current namespace is PEAR\Date, we don't need to prefix the namespace name $now = new Date(); echo $now->getDate(); // outputs the ISO formatted date // this example shows the full namespace specified as part of the class name $now = new PEAR\Date\Date(); echo $now->getDate(); // outputs the ISO formatted date ?> |
/* utils_left.php */ php namespace Utils\Left; function whichHand() { echo "I'm using my left hand!"; } ?> /* utils_right.php */ php namespace Utils\Right; function whichHand() { echo "I'm using my right hand!"; } ?> |
php include('./utils_left.php'); include('./utils_right.php'); Utils\Left\whichHand(); // outputs "I'm using my left hand!" Utils\Right\whichHand(); // outputs "I'm using my right hand!" use Utils\Left; whichHand(); // outputs "I'm using my left hand!" use Utils\Right; whichHand(); // outputs "I'm using my right hand!" |
php namespace Foo; function file_put_contents( $filename, $data, $flags = 0, $context = null ) { $return = \file_put_contents( $filename, $data, $flags, $context ); chmod($filename, 0444); return $return; } ?> |