## 1. 什么是命名空間?
命名空間對應的英文是 namespace ,所以翻譯成中文叫命名空間,在很多的語言中,都有這個 namespace ,那么它用來干嘛呢?說簡單點就是為了避免代碼命名重復。因為包括 php 在內的很多語言,是不允許 function name 或者 class name重復的,如果你同時 require 2 個 class ,如果調用的對應的 class name 是一樣,系統是會報錯的。所有,一般的對面對象的語言都會有 namespace ,用來避免這種情況出現。
php 在 5.3 之前是不支持 namespace 的,所以很多程序員的 class name 和 function name 經常會用 class_name_1 , class_name_2,class_name_3 用_隔開等類似這樣的方式來避免類的重復,很是這樣卻不美觀和優雅,而且維護起來比較費勁很難理解。于是 php在5.3 重磅突出了 namespace。
舉個例子,先常規的寫,不使用 namespace
現在我的同一個目錄下 3 個 php 文件,分別是:index.php,name.php,gender.php。
三個文件很簡單,就是輸出一段很簡單文字的代碼。
name.php
~~~php
<?php
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
gender.php
~~~php
<?php
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
然后在index.php分別rquire這2個文件
~~~php
<?php
require './name.php';
require './gender.php';
info::get_info();
info::get_info();
~~~
name.php 和 gender.php 里的類名字是一樣的,都叫 info ,或許你會反問我,你是傻逼嗎?你不會給這2個類取不一樣的名字啊。因為這里只是小測試小項目,你當然會取不一樣的名字。但是比如你用 composer 導入其他人的開源庫的代碼,肯定是會有 class name 是一樣的,這一點是毋庸置疑的,所以你還是無法避免這個問題的。
這時候,你運行下 index.php 就直接報致命錯誤了的,說類重新聲明了。
~~~php
Fatal error: Cannot redeclare class info in D:\wamp\www\testphp\namespace\gender.php on line 3
~~~
下面再簡單說下如何用 namespace 避免重復,還是這個例子,下面會著重講。
我們加入 namespace 看下:
name.php
~~~php
<?php
namespace Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
gender.php
~~~php
<?php
namespace Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
然后在 index.php 分別 rquire 這 2 個文件,并用 namespace 的方式調用。
~~~php
<?php
require './name.php';
require './gender.php';
Foo\info::get_info();
Fee\info::get_info();
~~~
我們刷新下 index.php , 看看結果是啥,看,輸出的就是我們想要的結果,沒有報錯:
~~~php
hello word 1hello word 2
~~~
function name 也是不能重復的,這里就不舉例了,原理是一樣的。
## 2. 為什么目前國內使用率不高?
截止到目前為止,老實話其實我也沒接觸過任何關于php的命名空間的項目或者代碼,我現在仔細想想為什么會這樣呢。大概或許是這幾點吧:
目前國內的php版本已經處于 5.3* , 而且還有很多處于 5.2 , php 的命名空間的更新是在 5.3 版本上加入的,所以使用率不是很高。
貌似目前的國內的開源的項目或者框架基本沒用 namespace ,或許也有這個因素的影響吧,大家開發寫代碼想到的就是如何運用好 MVC 和面向對象,想起用 namespace 的少之又少。
namespace 對比 PHP 中的其他語法還是有點羞澀難懂的,而且一些很詭異的書寫方式和命名方式,這或許也是一個比較大的影響因素,再加上平時項目中使用率不高,基本上也就不會用它了
## 3. 在 PHP類文件中使用namespace
下面我們進入正題,真正意義上來學一下php中的命名空間。php的命名空間其實還是非常簡單的。
如何聲明一個 namespace
前面一個例子呢,簡單的說了一下如何聲明,現在著重說一下,先提前說明下,稍顯變態。
像這樣子申明:
~~~php
namespce name
~~~
先看個例子:
~~~php
<?php
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
必須用關鍵字 namespace 來做聲明,后面加上命名空間的名字。這個關鍵字一行必須寫在一個 php 文件的最開頭,前面不能有任何的語句,額,這一點是有點變態哈,但是也還能忍受。所以,包括 ```ehco 222;, $info = array()``` 等這一系列的語句的都不能寫在 namespace 前面。不然就會報致命錯誤:
~~~php
Fatal error: Namespace declaration statement has to be the very first statement in the script in D:\wamp\www\testphp\namespace\gender.php on line 3
~~~
所以以下幾個是錯誤的,會報錯:
~~~php
<?php
$info = array();
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
echo 345;
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
header("Content-type: text/html; charset=utf-8");
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
還有最重要的一個容易忽略的就是 `<?php`,這個聲明是 php 的文件的標記也必須得定格寫,前面不能有空格, 不然也會報錯。這一點非常重要,極其容易忽略,就產生錯誤了。
`<?php` 前面有空格,也會報錯。
`<?php` //前面有個空格,也會報錯
~~~php
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
一個 namespace 的 name 的書寫方式
上面的幾個例子中,我們取的命名空間的 name 叫 Foo 和 Fee ,當然這只是一個例子,我們在取名字的時候必須得是有意義的。按照 PSR-0 的規范要求呢,這個名字必須得有一個上級的 Vendor Name ,可以理解為你的項目文件夾的名字,這樣的目的呢,第一是為了防止 namespace 的 name 也重復,第二是為了更好的定位文件的位置。也許有點看不懂,舉個例子:
假如 gender.php 和 name.php 文件中的 class name 都取名為 :info , 那么必須要設置 2 級的 namespace。
gender.php
~~~php
<?php
namespace App\Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
name.php
~~~php
<?php
namespace App\Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
namespace 的名字叫 App\Foo 和 App\Fee, App 就是 Vendor name 也就是項目的目錄。這樣就很好的區分了。
如果,name.php 和 gender.php 中的 class name 不一樣,也就不會重復了,理論上可以不用命名空間,但是現在用命名空間不僅僅是為了防止重復,現在同樣也是為了定位這個文件的目錄,為了好快速找到。所以,就只需一層 Vendor name 就可以了:
gender.php
~~~php
<?php
namespace App;
class gender {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
name.php
~~~php
<?php
namespace App;
class name {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
上面的我們都將它們命名空間為 APP ,因為它們的 class name 不一樣,所以組成的訪問類的方式: APP\gender::get_info(); 和 App\name::get_info(); 也就不一樣。也就不存在重復的關系。我們在下面將如何訪問一個 namespace 時會繼續講到。
name 命名規范 和 php 中變量的命名規則一樣,什么首字母不能是數字啊。只能有數字,字母,下劃線_組成,也不能是系統保留關鍵字等。( \ 這個符號可以用的,因為是在 namespace 中用來分割目錄的)
namespace 的訪問
上面我用了大幅篇章來聲明如何定義一個 namespace ,當然還有一些很詭異的申明方式,我們放到后面起說。現在來說,如何訪問一個 namespace。
訪問一個 namespace 其實和訪問一個 class 類一模一樣,先是導入 class ,再是 new 適用等。
### 第 1 種方式
像這樣子訪問調用:
~~~php
Vendor\namespce\class
gender.php
<?php
namespace App;
class gender {
//靜態方法,可以直接用::訪問
public static function get_info()
{
echo 'hello word 2';
}
}
name.php
<?php
namespace App;
class name {
public function get_info()
{
echo 'hello word 1';
}
}
<?php
require './gender.php';
require './name.php';
//static function 直接使用
App\gender::get_info();
//一般方式,先new,再調用
$name = new App\name;
$name->get_info();
~~~
和調用普通的類一樣,先 require 進來,只不過現在的類名變成了:在 class name 前面多加了一個 namespace name 并用\ 隔開,如果是靜態方法就直接 ::function name 調用就可以了。如果是常規方法就先 new 再調用 function name。
### 第 2 中方式:使用 use 關鍵字
用過其他語言中的 namespace 的或許知道有一個關鍵字 use 來到導入命名空間的,php 中也是可以的。我們試一下:
像這樣子訪問調用:
~~~php
use Vendor\namespce\class
class::function
index.php
<?php
require './gender.php';
require './name.php';
//第1種 use 用來導入gender類
use App\gender;
gender::get_info();
use App\name;
$name_object = new name;
$name_object->get_info();
//第2種 use ** as alise_name 取別名
use App\gender as alise_gender;
alise_gender::get_info();
use App\name as alise_name;
$alise_name_object = new alise_name;
$alise_name_object->get_info();
~~~
第 1 中是用 use 用來導入的,導入了 App\gender 類,然后就可以直接調用 gender:: 靜態方法或者 new name 再來調用普通方法。
第 2 種是用 use as alise_name 方法取了一個別名而已,用法和第一種類似一致。
我是推薦用第 1 種的,直接使用 use 導入就好了。用 as 別名反而容易造成錯誤和復雜度,而且你使用 use 的方式,已經是將 namespace 給省略掉了,變成正常的 class 調用方式。一般 as 用在 namespace 申明 function 時候用,在下面會講到。
OK. php 使用 命名空間基本的東西已經說完了。平時如果使用 namespace ,也就上面這些東西了。所以如果掌握了,基本也就沒問題了。
但是,我們因為是在學習它,所以還是要繼續深挖一些 namespace 其他的知識點的。在下面接著說。
## 4. 在php function文件中使用namespace
大多數適用 namespace 其實是在類文件( class )中使用的,在 function 文件中也是可以使用的,也能夠防止重復。但是用的很少,使用起來也很蛋疼。
還是看例子:
有一個 height.php 文件,用 namespace 申明一個命名空間 App
~~~php
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
~~~
然后在 index.php 中 require 并引用這個 namespace App
~~~php
<?php
require './height.php';
//第一種方式調用,和之前一樣
App\test();
//第二種方式調用,使用use, 必須配合as 使用,不然報錯
use App;
test(); //報錯
//正確的使用方式
use App as anthorApp;
anthorApp\test();
~~~
上面一個報錯的使用是我們自己想當然,想著沒有 class name 了,是不是就可以直接使用 function name 了,結果就報錯了。因為不管使用好是不使用 use,當得像這樣子訪問 class\function 。所以,既然 function 沒有 class ,那么我們就可以使用 use namespace as class 生成一個別名 anthorApp,再用這個 anthorApp\test() 就可以訪問了。
所以,你看到的這篇文件中這一處是錯誤的:PHP V5.3 中的新特性,第 3 部分: 名稱空間 :
~~~php
/* File3.php */
<?php
include './Foo.php';
use Foo;
bar(); // outputs "calling bar...."; //這種方式是錯的。
?>
~~~
所以總結下: 如果我們用 namespace 聲明 function 文件時,最好直接使用 App\test() 調用吧,如果想用 use 關鍵字,必須要用 as 一個別名。
## 5. 在php中混合使用各種
什么叫混合使用呢。就是既使用 namespace 聲明 class,又聲明 function,又單獨使用,雖然有點變態,但是為了學習它,為了找到 namespace 的精髓,我也是蠻拼的。
直接上代碼吧:
height.php 文件中,用 namespace 同時聲明的 function 和 class
~~~php
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
class height
{
public static function test()
{
echo 'hello word 3';
}
}
~~~
在 function.php 寫的是正常普通的 function 和 class
~~~php
<?php
function test()
{
echo ' this is a function test';
}
class height {
public static function test()
{
echo 'hello word 4';
}
}
~~~
好。那么這么變態的東西,如何訪問呢。仔細想想上面說的那么多的,其實很快就可以寫出來,而且不會報錯:
index.php
~~~php
<?php
require './height.php';
require './function.php';
// 調用namespace的function 和 class 直接調
App\test();
App\height::test();
//調用namespace的function 和 class 使用use
use App as anthorApp;
anthorApp\test();
use App\height;
height::test();
use App\height as anthorClssApp;
anthorClssApp::test();
//調用普通的
test();
height::test();
~~~
案例參考:
https://www.zybuluo.com/phper/note/65479
http://www.ibm.com/developerworks/cn/opensource/os-php-5.3new3/
http://www.cnblogs.com/thinksasa/p/3423480.html
http://www.w3cschool.cc/php/php-namespace.html