如下是我對命名空間的一些體會和理解,最好先看下php的官方文檔再來看此文,會更好一點。因爲水平有限,文中若有紕漏,但願指出php
在php5.3以上的版本中,php引入了命名空間(如下稱呼爲namespace)這個性能。我的認爲,這是很是重要的一項改變。之因此說重要,並非說namespace自己有多麼牛逼或者多高的技術含量。而是因爲命名空間的引入,引發了一些列的連鎖反應,這些連鎖反應給咱們如今phper開發者提供了另外一種可能。linux
如今的開發方式程序員
咱們在以往開發應用的時候,即便是很是簡單的應用,也常用php的那些框架,他們一般很重、很大、很難學,更要命的是,還不少,什麼Yii二、Thinkphp、CI、ZendFrame、Laravel......好吧我不想說了。windows
另外一種可能composer
如今呢,咱們彷佛有了另一種選擇。依靠composer包管理工具,加載packagist上面那些優秀的組件,而後經過composer提供的自動加載機制,將組建應用到項目中去。咱們的開發彷佛變成了擺積木,咱們要作的事情只是將組件恰當的組合起來,怎麼樣,聽着是否是很心動是麼?全世界優秀的輪子隨我用,這個feel倍爽!!!哦,離題有點遠了,那麼這和本文的主題namespacey又有什麼關係呢?固然有關係了,自動加載的基石namespace框架
實現另一種可能很重要的一步就是,將packagist組件自動加載到應用中。因爲php的_autoload有各類各樣的實現方式,爲此php-fig(php framework interop group一個php組織)提出了psr-0(已經廢棄)和psr-4,這兩個專門自動加載的解決方案,其核心思想就是:將命名空間和實際的磁盤物理路徑創建映射函數
(ps : 到目前爲止spr-0、spr-4只是推薦的自動加載解決方案,並無強制,但事實上,基本都採用了這種自動加載方式。除了spr-和spr-4外,composer還支持file 和classmap的方式)工具
命名空間出現的根本緣由是爲了解決命名衝突的問題,我的認爲主要是爲了解決如下命名衝突性能
舉個例子ui
咱們常用var_dump進行斷點調試,這個是系統提供給咱們的內置函數。可是呢,有的程序員對var_dump輸出的數據格式不是很滿意,但願本身寫一個var_dump函數(var_dump用時間長了,叫其餘的名字不習慣),本身格式化其輸出信息,可是報錯!
<?php //namespace mydubug; //若是將上面一行的註釋打開就不會再報錯,只不過調用的時候須要使用mydebug\var_dump的形式了 function var_dump($message) { echo "<br/>========================================</br>" echo $message; echo "<br/>========================================</br>" } /** * 報錯信息:PHP Fatal error: Cannot redeclare var_dump() */
我將採用類比的方法來講明這些高深的概念,儘可能能讓你們清楚。
全局命名空間
接觸過linux系統的同窗都應該知道根目錄"/"吧,咱們能夠將全局命名空間想象爲linux的根目錄,在該目錄下存放的都是php自己提供的各類接口/類/trait/函數/常量。
徹底限定名稱
以全局命名空間爲前綴的名稱,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();咱們能夠將其類比爲絕對路徑
限定名稱
不以全局命名空間爲前綴的名稱,例如,$a = new subnamespace\foo();或subnamespace\foo::staticmethod();咱們能夠將其類比爲相對路徑
非限定名稱
不包含任何前綴的名稱,例如, $a=new foo(); 或 foo::staticmethod();咱們能夠將其類比一個問文件名稱或者目錄名稱
首先確定一點,並非全部的元素都受到命名空間的影響,好比說變量就不會,只有如下php要素會受到影響:
咱們能夠認爲別名/導入,相似是windows下的快捷方式或者是linux下的軟鏈,經過該快捷方式咱們能夠連接到,別的空間下的class、interface、trait、constant、function,甚至能夠是單純的鏈接到別的命名空間而不特指該空間下的任何元素。下面舉個例子
<?php namespace foo; use My\Full\Classname as Another; // 下面的例子與 use My\Full\NSname as NSname 相同 use My\Full\NSname; $obj = new Another; // 實例化 My\Full\Classname 對象 NSname\subns\func(); // 調用函數 My\Full\NSname\subns\func ?>
當咱們的代碼中有以別名打頭的狀況時,php就會嘗試連接到別名對應的命名空間中的元素,或是別名對應的命名空間,而後拼接剩餘的名稱,若是有的話。例子中NSname\subns\func(); 檢查到NSname是別名,因此先連接到MyFullNSname, 而後拼接剩餘名稱My\Full\NSname\subns\func();
(ps:導入的名稱必須是徹底限定的,不會根據當前的命名空間做相對解析,前導的反斜槓是沒必要要的也不推薦的)
一圖勝千言,仍是上圖吧
從圖中,能夠看出主要是從徹底限定名和非徹底限定名這兩塊進行分析的。
由上圖,咱們能夠知道,限定名稱和非限定名稱的解析都會受到別名的影響。
並且,別名的優先級比當前命名空間的優先級高(不少地方都沒有說)。
也就是說,在一個命名空間下,限定名稱和非限定名稱會先嚐試尋找別名替換,若是找不到對應的別名,纔會將當前的命名空間追加到如今的名字前面組成徹底限定名
<?php //b.php文件 namespace Test\Top; class B { public function Test() { echo __FILE__, "\r\n"; } } <?php //a.php namespace Top; use Test\Top as Top; require __DIR__ . DIRECTORY_SEPARATOR . 'b.php'; Class B { function Test() { echo __FILE__,"\r\n"; } } (new Top\B())->Test();
a.php和b.php兩個文件在同一個目錄下:在b.php文件中,在namespace Top下面,擁有別名Test\Top as Top,因此new Top\B() 會被解釋成 new Test\Top\B(),也就是將別名進行了替換; 而並非new Top\Top\B(),將當前空間名添加到如今的名字前面。因此此時的運行結果是:xxxx/b.php
一、class 、interface 、traits和const 、function嘗試執行的加載策略不一樣
二、一個文件中,只有第一個namespace聲明命名空間前不能有任何字符,特別是bom頭(看不見可是存在),其餘的namespace不作限制。
三、namespace自己並不分區大小寫,相同名字的namespace認爲是同一個空間
<?php namespace Test{ function showName() { echo "This is a test in namespace Test"; } } namespace test{ function showName() { echo "This is a test in namespace test"; } } //報錯:PHP Fatal error: Cannot redeclare test\showName()
http://php.net/manual/zh/lang...《Modern php》