[中高級] PHP命名空間規則解析及高級功能

爲了便於對比,我定義了兩個幾乎同樣的代碼塊,只有命名空間的名字不一樣。
lib1.php
< ?php  
// application library 1  
namespace App\Lib1;  
 
const MYCONST = 'App\Lib1\MYCONST';  
 
function MyFunction() {  
 return __FUNCTION__;  
}  
 
class MyClass {  
 static function WhoAmI() {  
eturn __METHOD__;  
 }  
}  
?>  


lib2.php
< ?php  
// application library 2  
namespace App\Lib2;  
 
const MYCONST = 'App\Lib2\MYCONST';  
 
function MyFunction() {  
 return __FUNCTION__;  
}  
 
class MyClass {  
 static function WhoAmI() {  
eturn __METHOD__;  
 }  
}  
?>
開始以前先要理解幾個PHP命名空間相關術語。

◆徹底限定名稱(Fully-qualified name)

    任何PHP代碼均可以引用徹底限定名稱,它是一個以命名空間反斜線開頭的標識符,如\App\Lib1\MYCONST,\App\Lib2\MyFunction( )等。

    徹底限定名稱是沒有任何歧義的,開頭的反斜線和文件路徑的做用有點相似,它表示「根」全局空間,若是咱們在全局空間中實現了一個不一樣的MyFunction( ),能夠使用\MyFunction( )從lib1.php或lib2.php調用它。

    徹底限定名稱對一次性函數調用或對象初始化很是有用,但當你產生了大量的調用時它們就沒有實用價值了,在下面的討論中咱們將會看到,PHP提供了其它選項以解除咱們爲命名空間打字的煩惱。

◆限定名稱(Qualified name)

    至少有一個命名空間分隔符的標識符,如Lib1\MyFunction( )。

◆非限定名稱(Unqualified name)

    沒有命名空間分隔符的標識符,如MyFunction( )。

在相同的命名空間內工做

仔細思考下面的代碼:
myapp1.php

< ?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和MyClass標識符只能在lib1.php中引用,這是由於myapp1.php的代碼在相同的App\Lib1命名空間內。

    執行結果:
App\Lib1\MYCONST  
App\Lib1\MyFunction  
App\Lib1\MyClass::WhoAmI

命名空間導入

能夠使用 use操做符導入命名空間,如:
myapp2.php
< ?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,由於咱們的代碼還在全局空間中,但若是咱們添加了「Lib2\」前綴,它們就變成限定名稱了,PHP將會搜索導入的命名空間,直到找到匹配項。

執行結果:
App\Lib2\MYCONST  
App\Lib2\MyFunction  
App\Lib2\MyClass::WhoAmI

命名空間別名

命名空間別名多是最有用的構想了,別名容許咱們使用較短的名稱引用很長的命名空間。
myapp3.php
< ?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標識符名稱使用下列命名空間規則進行解析,請參考PHP用戶手冊瞭解更詳細的信息:

1.在編譯時調用徹底限定函數、類或常量;

2.非限定名稱和限定名稱根據導入規則進行翻譯,例如,若是A\B\C導入爲C,調用C\D\e( )就會被翻譯成A\B\C\D\e( );

3.在PHP命名空間內,全部限定名稱還沒有根據導入規則轉換,例如,若是在命名空間A\B中調用C\D\e( ),那麼會被翻譯成A\B\C\D\e( );

4.非限定類名稱根據當前的導入規則進行轉換,使用全名替換導入的短名稱,例如,若是類C在命名空間A\B中被導入爲X,那麼new X( )就會被翻譯爲new A\B\C( );

5.在命名空間中非限定函數調用在運行時解析,例如,若是MyFunction( )在命名空間A\B中被調用,PHP首先會查找函數\A\B\MyFunction( ),若是沒有找到,而後會在全局空間中查找\MyFunction( );

6.調用非限定或限定類名在運行時被解析,例如,若是咱們在命名空間A\B中調用new C( ),PHP將會查找類A\B\C,若是沒有找到,PHP會嘗試自動載入A\B\C。

PHP命名空間高級特性

    接下來讓咱們看一看PHP命名空間的一些高級特性。

__NAMESPACE__常量

    __NAMESPACE__是一個PHP字符串,它老是返回當前命名空間的名稱,在全局空間中它是一個空字符串。
< ?php  
namespace App\Lib1;  
echo __NAMESPACE__; // outputs: App\Lib1  
?>

    這個值在調試時很是有用,它也可因爲動態生成一個徹底限定類名,如: php

< ?php  
namespace App\Lib1;  
 
class MyClass {  
 public function WhoAmI() {  
return __METHOD__;  
 }  
}  
 
$c = __NAMESPACE__ . '\\MyClass';  
$m = new $c;  
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI  
?>
namespace關鍵字
    namespace關鍵字能夠用於明確引用一個當前命名空間或子命名空間中的項目,它等價於類中的self命名空間:
< ?php  
namespace App\Lib1;  
 
class MyClass {  
 public function WhoAmI() {  
return __METHOD__;  
 }  
}  
 
$m = new namespace\MyClass;  
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI  
?>
自動載入命名空間類

    PHP 5中最省時省力的特性是自動載入,在全局(非命名空間)PHP代碼中,能夠寫一個標準自動載入函數:
< ?php  
$obj= new MyClass1(); // classes/MyClass1.php is auto-loaded  
$obj= new MyClass2(); // classes/MyClass2.php is auto-loaded  
 
// autoload function  
function __autoload($class_name) {  
 require_once("classes/$class_name.php");  
}  
?>
    在PHP 5.3中,你能夠建立一個命名空間類的實例,在這種狀況下,徹底限定命名空間和類名傳遞給__autoload函數,例如,$class_name的值多是App\Lib1\MyClass。你能夠在相同的文件夾下放置全部的PHP類文件,從字符串中提取命名空間,但那樣會致使文件名衝突。

    另外,你的類文件層次結構會按照命名空間的結構從新組織,例如,MyClass.php文件能夠建立在/classes/App/Lib1文件夾下:
/classes/App/Lib1/MyClass.php

< ?php  
namespace App\Lib1;  
 
class MyClass {  
 public function WhoAmI() {  
return __METHOD__;  
 }  
}  
?>
在根文件夾下的文件就使用下面的代碼了:
myapp.php

< ?php  
use App\Lib1\MyClass as MC;  
 
$obj = new MC();  
echo $obj->WhoAmI();  
 
// autoload function  
function __autoload($class) {  
 // convert namespace to full file path  
 $class = 'classes/' . str_replace('\\', '/', $class) . '.php';  
 require_once($class);  
}  
?>
解釋:

1.類App\Lib1\MyClass的別名是MC;

2. new MC( )在編譯時被翻譯成new App\Lib1\MyClass( );

3.字符串App\Lib1\MyClass被傳遞給__autoload函數,使用文件路徑正斜線替換全部命名空間中的反斜線,而後修改字符串,classes\App\Lib1\MyClass.php文件被自動載入;

總結 有關PHP命名空間的使用就介紹到這裏,但願您可以對PHP的命名空間有一個新的認識,並但願你能在新項目中真正使用命名空間。
相關文章
相關標籤/搜索