命名空間不算新東西了,在PHP5.3.0以後就存在。曾經學次c#的時候接觸過命名空間這個概念,後來發現php也出現,可是當時認爲\符號來使用命名空間很醜陋,一直不敢興趣,如今我以爲\符愈來愈好看,人的眼光老是在進步。php
命名空間是新時代PHP不可或缺的一部分,它是現代主流php框架的基石。php框架
說白了,命名空間是解決文件、函數、類、常量等的重名問題,它虛擬了相似操做系統中文件系統的目錄結構,保證PHP組件和框架的全局惟一。app
好比我在在a目錄下有個db.php,在b目錄下也有個db.php。那麼按照古老的方式確定是經過類名保持和文件一致來區別.composer
例如a目錄下的命名爲:框架
class A_DB{}
b目錄下的命名爲:函數
class B_DB{}
編寫函數時可能經過每次加上一個function_exist的判斷去定義是否重名。
常量的定義同理,都是能夠有解決衝突的方案,可是如今composer盛行,PHP生態環境極好,各類組件層出不窮,咱們不能保證全部組件的命名都不同,而且這種經過文件名和類名來作區分十分不優雅,若是目錄層級很深,那麼類名可能會十分冗長。顯然,咱們應該選擇更先進的方法。post
每一個php文件的第一個命名空間必須聲明在php的頂部,在<?php標籤以後的第一行作聲明。命名空間是經過namespace
聲明,而後跟上一個空格,再而後跟上命名空間的名稱,最後用;符號結尾。測試
例如,聲明一個名稱爲A的命名空間:google
<?php namespace A;
在這個命名空間後面的全部php類,函數,接口,常量都在這個A命名空間裏面。spa
咱們先建立一個app目錄:
mkdir app
命名空間是經過namespace
來聲明的,經過use
關鍵字來引入的。
建立a.php
namespace A; const NUM = 1; function output() { echo "A output\n"; } namespace A2; const NUM = 2; function output(){ echo "A2 output\n"; } //經過關鍵字use來引入命名空間 use A; use A2; echo "NUM from A:" . A\NUM . "\n"; echo "NUM from A2:" . A2\NUM . "\n"; A\output(); A2\output();
運行結果以下:
NUM from A:1 NUM from A2:2 A output A2 output
上面咱們定義了兩個命名空間,分別是A和A2,這兩個命名空間下面有常量NUM,函數output,是的,故意命名成如出一轍的,用來測試命名空間是否有效。這個時候咱們經過use引入後,A\NUM能夠根據在A命名空間下找到它的NUM,等於1,同理A2\NUM等於2,而output函數也是經過A\output(),A2\output()找到各自的函數,而且輸出各自的內容。
咱們初嘗命名空間,知道用namespace
定義命名空間,用use
引入命名空間,經過命名空間\常量
,命名空間\函數名
調用。
注意:命名空間的定義和文件名乃至目錄結構沒有任何關係,好比這裏的namespace A徹底能夠換成namespace Apple,沒有任何關係,只要調用正確便可。
在同一個文件中聲明不建議採用上述寫法,建議用大括號包起來,以下:
<?php namespace A { const NUM = 1; function output() { echo "A output\n"; } } namespace A2 { const NUM = 2; function output(){ echo "A2 output\n"; } } namespace { use A; use A2; echo "NUM from A:" . A\NUM . "\n"; echo "NUM from A2:" . A2\NUM . "\n"; A\output(); A2\output(); }
以上代碼輸出的結果和上面是同樣的,這種寫法更佳。
雖然php容許在一個php文件定義多個命名空間,可是違背了「一個文件定義一個類」的良好實踐。一個文件定義一個類,只聲明一個命名空間,這樣更清晰簡潔。
建立a.php:
<php namespace A; const NUM = 1; class DB { public function output() { echo "DB from A\n"; } }
建立b.php:
<?php namespace B; use A; const NUM = 2; class DB { public function output() { echo "DB from B\n"; } } include "a.php";//必須引入a.php,才能使用a.php中的命名空間 echo "NUM from namespace A:" . A\NUM . "\n"; echo "NUM from namespace B:" . NUM . "\n"; $aObject = new A\DB(); $aObject->output(); $bObject = new DB(); $bObject->output();
而後執行b.php文件,輸出以下:
NUM from namespace A:1 NUM from namespace B:2 DB from A DB from B
此次沒有使用函數,經過類來實踐,證實類在命名空間下也是有效的。
常量很少說,它輸出仍是正常的,這裏定義了同名的DB類,可是它們並無衝突,輸出了各自的內容。
有人問爲何調用$bObject = new DB();
爲何不須要寫成$bObject = new B\DB();
,前面爲何不\號也能夠調用,由於咱們執行的是b.php文件,當前代碼是屬於B這個命名空間的,默認已經加上了。
咱們能夠嘗試加上\號,報錯以下:
PHP Fatal error: Uncaught Error: Class 'B\B\DB' not found in b.php
因此,咱們在當前命名空間是不須要加\B的。
若是沒有定義任何命名空間,全部的類與函數的定義都是在全局空間。在名稱前加上前綴 \ 表示該名稱是全局空間中的名稱。
建立comon.php
<?php function test() { echo "test from common.php\n"; }
建立a.php
<php namespace A; function test() { echo "test from a.php\n"; } include "common.php"; test(); //調用a.php \test(); //調用common.php
執行a.php,結果下:
test from a.php
test from common.php
其實php官方把開頭帶有\符號的調用叫作徹底限定名稱,實際上就是當前整個做用於有效的,好比上面引入了common.php,裏面有一個test(),那麼就應該經過\test()調用。固然這是在重名下的調用,若是common中的test叫作test2,那麼能夠直接test2();調用,應爲在A這個命名空間下沒有和它衝突的函數名。
注意:訪問任意全局類、函數或常量,均可以使用徹底限定名稱,例如 \strlen() 或 \Exception 或 \INI_ALL。
例如:
<?php namespace A; $str = "123"; function strlen($string){ return \strlen($string) + 1; } echo \strlen($str). "\n"; echo strlen($str) . "\n";
輸出結果:
3
4
顯然當前a.php文件中strlen和系統函數strlen重名了,咱們經過\strlen($str)調用系統的函數, strlen($str)是調用命名空間A的函數,只不過它內部又是經過系統函數strlen實現的。
在咱們的實際項目中遇到的命名空間的層次會比較深,好比:
<?php use App\Component\Net\HttpResponsePostTool; //這裏是僞代碼 $postobject = new HttpResponsePostTool('http://google.com'); $postobject->go();
這個HttpResponsePostTool很長,能夠用as關鍵字定義別名:
<?php use App\Component\Net\HttpResponsePostTool as MyPost; //這裏是僞代碼 $postobject = new MyPost('http://google.com'); $postobject->go();
這樣是否優雅不少。
雖然良好實踐是在一個php文件中作一個命名空間的聲明,可是這不妨礙咱們導入多個命名空間,並且這是常常用的。
php容許只使用一次use,經過逗號分割命名空間進行導入,最後一個命名空間加上分號,好比:
<?php use A, B, C;
可是不建議這麼寫,不利於閱讀,最好每行都使用use引入:
<?php use A; use B; use C;
瞭解以上,基本就能使用命名空間進行開發了。
補充:
命名空間的三種訪問方式(和相對路徑與絕對路徑類似)
A. 非限定名稱訪問方式
B. 限定名稱訪問方式
C. 徹底限定名稱訪問方式
<?php namespace app\get1 function getUser () { return $username1; } namespace get2 function getUser () { return $username2; } getUser(); // 非限定名稱訪問方式 \app\get1\getUser(); //徹底限定名稱訪問方式,從根路徑開始,相似絕對路徑 app\get1\getUser(); //限定名稱訪問方式,不是從根路徑開始,相似相對路徑
命名空間的引入機制
1)空間的引入:關鍵字use,注意:當移入空間後,必需要用限定名稱訪問方式訪問引入空間裏面的函數(或類、常量),不能使用非限定名稱方式訪問,這樣會訪問到當前命名空間下的函數(或類、常量)。2)空間類元素的引入:關鍵字use。注意:只能引入類,而後可使用非限定名稱訪問。