PHP的命名空間(namespace)是php5.3之后才有的。這個概念在C#中已經很早就有了,php中的namespace其實和c#的概念是一樣的。
為什么php中要使用namespace?
假設如果不使用namespace,那么每個類在一個項目中的名字就必須是固定的。因為php在new的時候不管是調用autoload還是調用已加載過的類,都存在一個類名對應的文件。所以在沒有namespace的時候,我們會想各種命名規則來區分不同的類,比如project1_school1_class1_Student或者project2_school_class_Student。
引入namespace之后就可以將這個有效規避了,一個namespace就相當於對應一個文件路徑,查找這個類的時候,就會去對應的文件路徑查找類定義文件了。
namespace的定義和使用
定義:
<?php namespace Myproject;
或者
<?php
namespace Myproject {
}
使用:
<?php use Myproject/School;
<?php use Myproject/School as School1; // 別名
命名空間是運行時解析的。use就相當於一種聲明,並不解析和加載。比如下面這個例子:
test.php
<?php
use my\name;
require_once("/home/yejianfeng/handcode/test/namespace1.php");
$a = new my\name\A();
$a->Print1();
namespace1.php
<?php
namespace my\name;
class A {
public function Print1(){
echo 11;
}
}
雖然require_once在use下面,也是可以正常運行的,因為程序只有在new my\name\A()的時候才去加載命名空間my\name
全局類和命名空間類
如果要new一個全局類使用 new \A()
如果要new一個命名空間類,使用new my\namespace\A()
命名空間的順序
自從有了命名空間之后,最容易出錯的該是使用類的時候,這個類的尋找路徑是什么樣的了。
如果能弄清楚manual中的這個例子就能全部弄清楚尋找順序了。
<?php
namespace A;
use B\D, C\E as F;
// 函數調用
foo(); // 首先嘗試調用定義在命名空間"A"中的函數foo()
// 再嘗試調用全局函數 "foo"
\foo(); // 調用全局空間函數 "foo"
my\foo(); // 調用定義在命名空間"A\my"中函數 "foo"
F(); // 首先嘗試調用定義在命名空間"A"中的函數 "F"
// 再嘗試調用全局函數 "F"
// 類引用
new B(); // 創建命名空間 "A" 中定義的類 "B" 的一個對象
// 如果未找到,則嘗試自動裝載類 "A\B"
new D(); // 使用導入規則,創建命名空間 "B" 中定義的類 "D" 的一個對象
// 如果未找到,則嘗試自動裝載類 "B\D"
new F(); // 使用導入規則,創建命名空間 "C" 中定義的類 "E" 的一個對象
// 如果未找到,則嘗試自動裝載類 "C\E"
new \B(); // 創建定義在全局空間中的類 "B" 的一個對象
// 如果未發現,則嘗試自動裝載類 "B"
new \D(); // 創建定義在全局空間中的類 "D" 的一個對象
// 如果未發現,則嘗試自動裝載類 "D"
new \F(); // 創建定義在全局空間中的類 "F" 的一個對象
// 如果未發現,則嘗試自動裝載類 "F"
// 調用另一個命名空間中的靜態方法或命名空間函數
B\foo(); // 調用命名空間 "A\B" 中函數 "foo"
B::foo(); // 調用命名空間 "A" 中定義的類 "B" 的 "foo" 方法
// 如果未找到類 "A\B" ,則嘗試自動裝載類 "A\B"
D::foo(); // 使用導入規則,調用命名空間 "B" 中定義的類 "D" 的 "foo" 方法
// 如果類 "B\D" 未找到,則嘗試自動裝載類 "B\D"
\B\foo(); // 調用命名空間 "B" 中的函數 "foo"
\B::foo(); // 調用全局空間中的類 "B" 的 "foo" 方法
// 如果類 "B" 未找到,則嘗試自動裝載類 "B"
// 當前命名空間中的靜態方法或函數
A\B::foo(); // 調用命名空間 "A\A" 中定義的類 "B" 的 "foo" 方法
// 如果類 "A\A\B" 未找到,則嘗試自動裝載類 "A\A\B"
\A\B::foo(); // 調用命名空間 "A\B" 中定義的類 "B" 的 "foo" 方法
// 如果類 "A\B" 未找到,則嘗試自動裝載類 "A\B"
?>
