作開發也有2年的時間了,發現一個問題,作的越久,對基礎知識掌握的越少,越喜歡理解一些很「高深」的東西,看似高深,其實low到不行。慢慢你會發現,越是學習高深的東西,對基礎知識要求越高,好比本節說的命名空間,你對這個不瞭解,那麼你對composer的文件自動加載就是一頭霧水php
踩過一些坑發如今學習這件路上,不能懶,只要你一懶下來,你以前學習的東西,會忘記的一乾二淨,什麼都沒有,記下來,記下來是最好的方式,哪怕這個知識點簡單的不能再簡單了,記下來composer
在回答這個問題以前,我想先回答爲何要有命名空間,若是咱們反着問,沒有命名空間是什麼樣子呢。想象一下你如今寫了一個名爲User的類,我也寫了一個User的類,咱們把這兩個類放在一個文件裏面。這個時候就會出錯,提示不能有兩個類名相同的類出現框架
若是咱們給這兩個類加上命名空間,namespae jack
和namespae tom
,這個時候就不出現剛纔的問題了。函數
在PHP官網中,提到能夠經過命名空間解決在編寫類庫或函數的時候遇到這兩類問題:學習
- 用戶編寫的代碼與PHP內置的類/函數/常量或第三方類/函數/常量之間的名字衝突。
- 爲很長的標識符名稱建立一個別名,提升源代碼的可讀性
上面的第一點我明白,第二點有點糊塗,後面發現這個要在使用命名空間的時候纔會說到,一句話來講,就是命名空間能夠建立別名,好比使用use App\Models\User
,在引入User後同時也建立了一個User
的別名,日後咱們使用User
就至關於使用\APP\Models\User
spa
其實命名空間就是藉助文件系統中的目錄來解決命名這個難題的,應用到程序設計領域就是命名空間的概念設計
要記住一點就是,不能說命名空間就等同於目錄,只不過藉助目錄這樣一個原理,來實現同名的函數、類等等code
在PHP中定義命名空間很是的簡單,使用namespage
關鍵詞來聲明就能夠了,以下:對象
namespace Jack;
const CARD_ID=5;
class User{}
function getInfo(){}
複製代碼
雖說PHP的代碼均可以包含在命名空間中,但也只有類、接口、函數、常量會受到影響。像變量就不起做用,因此在使用變量前必定得初始化。接口
命名空間也能夠像目錄文件同樣,指定層次化的命名空間的名稱,好比Laravel框架中定義的命名空間namespace App\Http\Controllers
,這在你使用composer引入第三方類庫更常見了
使用命名空間是很是簡單的操做,使用use關鍵字就能夠導入外部的徹底限定名稱,而且還能夠名別名
namespace foo;
// 下面兩個是等價的
use My\Full\Classname;
use My\Full\Classname as Classname;
複製代碼
經過上面的例子,咱們知道use關鍵字能夠在引入外部命名空間的同時還給它取別名,後面就可使用別名,來代替以前的徹底限定名稱了
由於導入的命名空間必須是徹底限定名稱,前導的反斜槓是沒必要須要的,例如use Http\Models
不只能夠對命名空間使用別名,還能夠給類名稱、接口、函數、常量設置別名,例如:
use My\Full\Classname as Another;
use function My\Full\functionName as func;
use const My\Full\CONSTANT;
複製代碼
也能夠不使用use關鍵字導入類,直接在調用類的代碼處使用徹底限定名稱,例如:\App\Model\Use ::first()
如今已經知道如何使用命名空間,但對PHP使用哪個命名空間中的元素是不知道的,好比有\foo()、\config\foo()兩個函數,到底使用哪個函數咱們是不知道的,對此PHP有三種使用命名空間名稱的方式
名稱中不含有命名空間分隔符,例如 $a=new foo()。若是當前命名空間是currentnamespace,foo將被解析爲currentnamespace\foo;若是當前命名空間是全局的,則foo會被解析爲foo。
在PHP中對非限定的類、函數、常量,採用的是不一樣的優先策略來解析這些名稱
類名稱總會解析到當前命名空間中
namespace A\B\C;
class Exception extends \Exception {}
$a = new Exception('hi'); // $a 是類 A\B\C\Exception 的一個對象
$b = new \Exception('hi'); // $b 是類 Exception 的一個對象
複製代碼
函數和常量若是在當前命名空間中不存在,那麼會在全局空間中使用他們
namespace A\B\C;
const E_ERROR = 45;
function strlen($str) {
echo 'hello';
}
echo E_ERROR, "\n"; // 輸出 "45"
echo INI_ALL, "\n"; // 輸出 "7" - 使用全局常量 INI_ALL
echo strlen('hi'), "\n"; // 輸出 "hello"
複製代碼
限定名稱,名稱中含有命名空間分隔符,例如 $a = new subnamespace\foo()。若是當前的命名空間是 currentnamespace,則 foo 會被解析爲 currentnamespace\subnamespace\foo;若是當前的命名空間是全局的,foo 會被解析爲subnamespace\foo。
namespace Foo\Bar\subnamespace;
function foo() {}
namespace Foo\Bar;
subnamespace\foo(); // 解析爲函數 Foo\Bar\subnamespace\foo
複製代碼
名稱以命名空間分隔符開始的標識符,例如$a = new \currentnamespace\foo(),在這種狀況下,foo老是被解析爲代碼中的文字名currentnamespace\foo。
namespace Foo\Bar\subnamespace;
function foo() {}
\Foo\Bar\foo(); // 解析爲函數 Foo\Bar\foo
複製代碼
說了這麼多,意義是什麼呢,對於平時的代碼編寫有什麼幫助,我的認爲總結下來,在這些方面平時能夠注意一下。在使用函數的時候,使用非限定名稱,若是當前空間沒有找到函數,PHP會自動在全局空間查找;對於類、接口要是使用徹底限定名稱,明確它們所在的空間,不會由於當前環境的變化而受到影響
__NAMESPACE__
的值是包含當前命名空間名稱的字符串,若是是在全局空間,則是一個空字符串
// file1.php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // 輸出 "MyProject"
// file2.php
echo '"', __NAMESPACE__, '"'; // 輸出 ""
複製代碼
關鍵字namespace
能夠顯示訪問當前命名空間或子命名空間中的元素
namespace Help;
function test(){echo 'test';};
echo namespace\test(); //calls function Help\test()
複製代碼
這些東西到底有什麼意義呢,有的,就是咱們能夠的動態建立名稱,例如:
namespace MyProject;
class Student {
public function __construct() {
echo 'new Student';
}
}
function get($classname) {
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
get('Student');
複製代碼
仔細發現,你會以爲這個代碼有問題,都在同一個命名空間,並且你使用的又是限定名稱,__NAMESPACE__ . '\\' . $classname
會被解析成MyProject\MyProject\Student,運行代碼發現又沒有這樣的問題,這究竟是怎麼回事
這是由於在動態的類名稱、函數名稱或常量名稱中,必需要使用徹底限定名稱,又由於限定名稱和徹底限定名稱沒有區別,因此前導反斜槓是沒必要要加的
這樣就很好的解釋前面的問題,__NAMESPA CE__ . '\\' . $classname
雖然是限定名稱,可是它是動態類名稱,沒必要要加前導反斜槓
若是上面的例子中的__NAMESPACE__ . '\\' . $classname
改成$classname
,結果會怎麼樣呢
Fatal error: Uncaught Error: Class 'Student' not found
PHP會把$classname
解析爲徹底限定名稱,在咱們這個例子中就是全局空間下的Student類
爲何PHP會有這樣的設計呢,我想這跟PHP的自動加載有很大的關係,徹底限定名稱就不須要在當前命名空間查找元素了,效率比非限定名稱要好一些
在這篇文章寫完以後,我發現對命名空間這塊,有了新的認識,好比命名空間是怎麼來的,是由於類重名、函數重名,參照文件目錄的原理,設計了這麼一個東西。它的出生是來解決問題的,不是製造問題的,在使用命名空間的時候,就要對它的原理掌握清楚,使用非限定名稱會有哪些問題,那些地方是必需要使用徹底限定名稱的。
經過這麼記下來,總結下來,要比之前本身蜻蜓點水式的學習方式要好一下,我不能說這會好太多,只是在某一兩個知識點面前,會有深入的認識,就是這個地方深刻的瞭解,你對其餘塊的知識慢慢的也會了解
就好比下面一篇,我要學習的PSR-4自動加載規則,就要求你對PHP的命名空間要有很好的理解,否則的話,不少地方你只能記住,而不能有深入的認識,時間一長你就忘了