新聞中心

成都創(chuàng)新互聯(lián)公司于2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目網(wǎng)站建設(shè)、成都網(wǎng)站制作網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元大石橋做網(wǎng)站,已為上家服務(wù),為大石橋各地企業(yè)和個人服務(wù),聯(lián)系電話:028-86922220
舉個簡單的例子,文件 foo.txt 可以同時在目錄 /home/greg 和 /home/other 中存在,但在同一個目錄中不能存在兩個 foo.txt 文件。另外,在目錄 /home/greg 外訪問 foo.txt 文件時,我們必須將目錄名以及目錄分隔符放在文件名之前,例如 /home/greg/foo.txt。這個原理應(yīng)用到程序設(shè)計領(lǐng)域就是命名空間的概念。
命名空間的定義
php 中命名空間(namespace)是在 PHP5.3 中加入的,如果你了解過 C++ 的話,那命名空間就不算什么新事物了。不過命名空間在 PHP 當(dāng)中還是相當(dāng)重要的。
PHP 命名空間可以解決以下兩類問題:
- 用戶編寫的代碼與 PHP 內(nèi)部的類/函數(shù)/常量或第三方類/函數(shù)/常量之間的命名沖突;
- 為很長的標(biāo)識符名稱(通常是為了緩解第一類問題而定義的)創(chuàng)建一個別名(或簡短)的名稱,以提高源代碼的可讀性。
1) 定義命名空間(使用關(guān)鍵字 namespace)
雖然任意合法的 PHP 代碼都可以包含在命名空間中,但只有類(包括抽象類和 traits)、接口、函數(shù)和常量等類型的代碼受命名空間的影響。
命名空間的定義需要通過關(guān)鍵字 namespace 來聲明,語法格式如下:
namespace 命名空間名;
【示例】下面我們來演示一下如何定義了命名空間:
在聲明命名空間之前除了用于定義源文件編碼方式的 declare 語句外,所有非 PHP 代碼(包括空白符)都不能出現(xiàn)在命名空間聲明之前。
另外,與 PHP 其它的語言特征不同,同一個命名空間可以定義在多個文件中,即允許將同一個命名空間的內(nèi)容分割存放在不同的文件中。
2) 定義子命名空間
與目錄和文件的關(guān)系很象,PHP 中的命名空間也允許指定層次化的命名空間名稱。因此,命名空間的名字可以使用分層次的方式定義:
namespace App\Model;
namespace App\Controller\Home;
【示例】定義一個子命名空間:
3) 在同一個文件中定義多個命名空間
在一個文件中也可以定義多個命名空間,在同一文件中定義多個命名空間有兩種語法形式,下面通過示例演示一下:
【示例】定義多個命名空間——簡單組合語法。
【示例】定義多個命名空間——大括號
{ }語法。
在實際的編程實踐中,并不提倡在同一個文件中定義多個命名空間。定義多個命名空間主要用于將多個 PHP 腳本合并在同一個文件中。在定義多個命名空間時建議使用大括號形式的語法。
將全局的非命名空間中的代碼與命名空間中的代碼組合在一起,只能使用大括號形式的語法,同時全局代碼必須用一個不帶名稱的 namespace 語句加上大括號括起來,如下所示:
使用命名空間:基礎(chǔ)
在討論如何使用命名空間之前,必須了解 PHP 是如何知道要使用哪一個命名空間中的元素的。我們可以將 PHP 命名空間與文件系統(tǒng)作一個簡單的類比。在文件系統(tǒng)中訪問一個文件有三種方式:
- 相對文件名形式如 foo.txt。它會被解析為 currentdirectory/foo.txt,其中 currentdirectory 表示當(dāng)前目錄。因此如果當(dāng)前目錄是 /home/foo,則該文件名被解析為 /home/foo/foo.txt;
- 相對路徑名形式如 subdirectory/foo.txt。它會被解析為 currentdirectory/subdirectory/foo.txt;
- 絕對路徑名形式如 /main/foo.txt。它會被解析為 /main/foo.txt。
PHP 命名空間中的元素使用同樣的原理。例如,命名空間下的類名可以通過三種方式引用:
- 非限定名稱,或不包含前綴的類名稱,例如
$a=new foo();或foo::staticmethod();。如果當(dāng)前命名空間是 currentnamespace,那么 foo 將被解析為 currentnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,則 foo 會被解析為 foo。 - 限定名稱,或包含前綴的名稱,例如
$a = new subnamespace\foo();或subnamespace\foo::staticmethod();。如果當(dāng)前的命名空間是 currentnamespace,則 foo 會被解析為 currentnamespace\subnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,foo 會被解析為 subnamespace\foo。 - 完全限定名稱,或包含了全局前綴操作符的名稱,例如
$a = new \currentnamespace\foo();或\currentnamespace\foo::staticmethod();。在這種情況下,foo 總是被解析為代碼中的文字名 currentnamespace\foo。
警告:如果命名空間中的函數(shù)或常量未定義,則該非限定的函數(shù)名稱或常量名稱會被解析為全局函數(shù)名稱或常量名稱。
下面是一個使用這三種方式的實例,我們需要兩個 PHP 源文件,分別是 demo.php 和 index.php,示例代碼如下:
1) demo.php
2) index.php
';
}
class foo
{
static function demo(){
echo '命名空間為:Foo\Bar
';
}
}
/* 非限定名稱 */
foo(); // 解析為 Foo\Bar\foo resolves to function Foo\Bar\foo
foo::demo(); // 解析為類 Foo\Bar\foo 的靜態(tài)方法 staticmethod。
echo FOO.'
'; // 解析為常量 Foo\Bar\FOO
/* 限定名稱 */
Demo\foo(); // 解析為函數(shù) Foo\Bar\Demo\foo
Demo\foo::demo(); // 解析為類 Foo\Bar\Demo\foo,
// 以及類的方法 demo
echo Demo\FOO.'
'; // 解析為常量 Foo\Bar\Demo\FOO
/* 完全限定名稱 */
\Foo\Bar\foo(); // 解析為函數(shù) Foo\Bar\foo
\Foo\Bar\foo::demo(); // 解析為類 Foo\Bar\foo, 以及類的方法 demo
echo \Foo\Bar\FOO.'
'; // 解析為常量 Foo\Bar\FOO
?>
運行結(jié)果如下:
Foo\Bar 命名空間下的 foo 函數(shù)
命名空間為:Foo\Bar
2
Foo\Bar\Demo 命名空間下的 foo 函數(shù)
命名空間為:Foo\Bar\Demo
1
Foo\Bar 命名空間下的 foo 函數(shù)
命名空間為:Foo\Bar
2
注意:訪問任意全局類、函數(shù)或常量,都可以使用完全限定名稱,例如 \strlen() 或 \Exception 等。
使用命名空間:別名/導(dǎo)入
PHP 允許通過別名引用或?qū)氲姆绞絹硎褂猛獠康拿臻g,這是命名空間的一個重要特征。這有點類似于在類 unix 文件系統(tǒng)中可以創(chuàng)建對其它的文件或目錄的符號連接。
使用 use 關(guān)鍵字可以實現(xiàn)命名空間的導(dǎo)入,從 PHP5.6 開始允許導(dǎo)入函數(shù)和常量,并為它們設(shè)置別名。語法格式如下:
use namespace;
在 PHP 中,別名是通過操作符 use 與 as 來實現(xiàn)的,語法格式如下:
use 命名空間 as 別名;
【示例】使用 use 操作符導(dǎo)入和使用別名。
注意:對命名空間中的名稱(包含命名空間分隔符的完全限定名稱,如 Foo\Bar ,以及相對的不包含命名空間分隔符的全局名稱,如 FooBar)來說,前導(dǎo)的反斜杠是不必要的也是不推薦的,因為導(dǎo)入的名稱必須是完全限定的,不會根據(jù)當(dāng)前的命名空間作相對解析。
為了簡化操作,PHP 還支持在一行中導(dǎo)入多個命名空間,中間使用
,隔開,示例代碼如下:
導(dǎo)入操作是編譯執(zhí)行的,但動態(tài)的類名稱、函數(shù)名稱或常量名稱則不是。
另外,導(dǎo)入操作只影響非限定名稱和限定名稱。完全限定名稱由于是確定的,故不受導(dǎo)入的影響。
namespace 關(guān)鍵字和 __NAMESPACE__ 常量
PHP 支持兩種抽象的訪問當(dāng)前命名空間內(nèi)部元素的方法,__NAMESPACE__ 魔術(shù)常量和 namespace 關(guān)鍵字。
__NAMESPACE__ 常量的值是包含當(dāng)前命名空間名稱的字符串。在全局的,不包括在任何命名空間中的代碼,它是一個空的字符串。示例代碼如下:
運行結(jié)果如下:
App\Controller\Home
namespace 關(guān)鍵字可用來顯式訪問當(dāng)前命名空間或子命名空間中的元素,它等價于類中的 self 操作符。示例代碼如下:
命名空間名稱解析規(guī)則
在說明名稱解析規(guī)則之前,我們先來看看命名空間名稱的定義:
- 非限定名稱:名稱中不包含命名空間分隔符的標(biāo)識符,例如 Foo;
- 限定名稱:名稱中含有命名空間分隔符的標(biāo)識符,例如 Foo\Bar;
- 完全限定名稱:名稱中包含命名空間分隔符,并以命名空間分隔符開始的標(biāo)識符,例如 \Foo\Bar。namespace\Foo 也是一個完全限定名稱。
名稱解析遵循下列規(guī)則:
- 對完全限定名稱的函數(shù),類和常量的調(diào)用在編譯時解析。例如 new \A\B 解析為類 A\B;
- 所有的非限定名稱和限定名稱(非完全限定名稱)根據(jù)當(dāng)前的導(dǎo)入規(guī)則在編譯時進行轉(zhuǎn)換。例如,如果命名空間 A\B\C 被導(dǎo)入為 C,那么對 C\D\e() 的調(diào)用就會被轉(zhuǎn)換為 A\B\C\D\e();
- 在命名空間內(nèi)部,所有的沒有根據(jù)導(dǎo)入規(guī)則轉(zhuǎn)換的限定名稱均會在其前面加上當(dāng)前的命名空間名稱。例如,在命名空間 A\B 內(nèi)部調(diào)用 C\D\e(),則 C\D\e() 會被轉(zhuǎn)換為 A\B\C\D\e();
- 非限定類名根據(jù)當(dāng)前的導(dǎo)入規(guī)則在編譯時轉(zhuǎn)換(用全名代替短的導(dǎo)入名稱)。例如,如果命名空間 A\B\C 導(dǎo)入為 C,則 new C() 被轉(zhuǎn)換為 new A\B\C();
- 在命名空間內(nèi)部(例如 A\B),對非限定名稱的函數(shù)調(diào)用是在運行時解析的。例如對函數(shù) foo() 的調(diào)用是這樣解析的:
- 在當(dāng)前命名空間中查找名為 A\B\foo() 的函數(shù);
- 嘗試查找并調(diào)用全局空間中的 foo() 函數(shù)。
- 在命名空間(例如 A\B)內(nèi)部對非限定名稱或限定名稱類(非完全限定名稱)的調(diào)用是在運行時解析的。下面是調(diào)用 new C() 及 new D\E() 的解析過程:
- new C() 的解析:
- 在當(dāng)前命名空間中查找 A\B\C 類;
- 嘗試自動裝載類 A\B\C。
- new D\E() 的解析:
- 在類名稱前面加上當(dāng)前命名空間名稱變成:A\B\D\E,然后查找該類;
- 嘗試自動裝載類 A\B\D\E。
- 為了引用全局命名空間中的全局類,必須使用完全限定名稱 new \C()。
- new C() 的解析:
網(wǎng)站標(biāo)題:PHPnamespace:命名空間
URL鏈接:http://fisionsoft.com.cn/article/djpehhi.html


咨詢
建站咨詢
