標籤:style http color io os 使用 ar strong 檔案
PHP核心探索:命名空間
命名空間是一種特殊的範圍
感謝 參考或原文 www.php-internal.com伺服器君一共花費了81.974 ms進行了3次資料庫查詢,努力地為您提供了這個頁面。 試試閱讀模式?希望聽取您的建議
在維基百科中,對命名空間的定義是: 命名空間(英語:Namespace)表示標識符(identifier)的上下文(context)。一個標識符可在多個命名空間中定義, 它在不同命名空間中的含義是互不相干的。在程式設計語言中,命名空間是一種特殊的範圍,它包含了處於該範圍內的標識符, 且本身也用一個標識符來表示,這樣便將一系列在邏輯上相關的標識符用一個標識符組織了起來。 函數和類的範圍可被視作隱式命名空間,它們和可見度、可訪問性和對象生命週期不可分割的聯絡在一起。
命名空間可以看作是一種封裝事物的方法,同時也可以看作是組織代碼結構的一種形式,在很多語言中都可以見到這種抽象概念和組織形式。 在PHP中,命名空間用來解決在編寫類庫或應用程式時建立可重用的代碼如類或函數時碰到的兩類問題:
- 使用者編寫的代碼與PHP內部的類/函數/常量或第三方類/函數/常量之間的名字衝突。
- 為很長的標識符名稱(通常是為了緩解第一類問題而定義的)建立一個別名(或簡短)的名稱,提高原始碼的可讀性。
PHP從5.3.0版本開始支援命名空間特性。看一個定義和使用命名空間的樣本:
04 |
public static $var = ‘think in php internal‘; |
07 |
const E_ALL = "E_ALL IN Tipi"; |
10 |
echo ‘strlen in tipi‘; |
14 |
echo strlen(Exception::$var); |
如上所示,定義了命名空間tipi,在這個命名空間內定義了一個Exception類,一個E_ALL常量和一個函數strlen。 這些類、常量和函數PHP預設已經實現。假如沒有這個命名空間,聲明這些類、常量或函數時會報函數重複聲明或類重複聲明的錯誤, 並且常量的定義也不會成功。
從PHP語言來看,命名空間通過 namespace 關鍵字定義,在命名空間內,可以包括任何合法的PHP代碼,但是它的影響範圍僅限於類、常量和函數。 從文法上來講,PHP支援在一個檔案中定義多個命名空間,但是不推薦這種程式碼群組織方式。 當需要將全域的非命名空間中的代碼與命名空間中的程式碼群組合在一起,全域代碼必須用一個不帶名稱的 namespace 語句加上大括弧括起來。
此時,思考一下,在PHP核心中,命名空間的定義是如何?的呢? 當在多個命名空間中存在多個相同的函數或類時,如何區分? 命名空間內的函數如何調用?
命名空間的定義
命名空間在PHP中的實現方案比較簡單,不管是函數,類或者常量, 在聲明的過程中都將命名空間與定義的函數名以\合并起來,作為函數名或類名儲存在其對應的容器中。 如上面樣本中的Exception類,最後儲存的類名是tipi\Exception。 對於整個PHP實現的架構來說,這種實現方案的代價和對整個代碼結構的調整都是最小的。
下面我們以Exception類為例說明整個命名空間的實現。 命名空間實現的關鍵字是namespace,從此關鍵字開始我們可以找到在編譯時間處理此關鍵字的函數為 zend_do_begin_namespace。 在此函數中,關鍵是在對CG(current_namespace)的賦值操作,這個值在後面類聲明或函數等聲明時都會有用到。
在前面我們講過,類聲明的實現在編譯時間會調用Zend/zend_complie.c檔案中的zend_do_begin_class_declaration函數, 在此函數中對於命名空間的處理代碼如下:
01 |
if (CG(current_namespace)) { |
02 |
/* Prefix class name with name of current namespace */ |
05 |
tmp.u.constant = *CG(current_namespace); |
06 |
zval_copy_ctor(&tmp.u.constant); |
07 |
zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); |
10 |
lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); |
這段代碼的作用是如果當前存在命名空間,則給類名加上命名空間的首碼, 如前面提到樣本中的tipi\Exception類,添加tipi\的操作就是在這裡執行的。 在zend_do_build_namespace_name函數中最終會調用zend_do_build_full_name函數實作類別名的合并。 在函數和常量的聲明中存在同樣的名稱合併作業。這也是命名空間僅對類、常量和函數有效原因。
使用命名空間
以函數調用為例,當需要調用函數時,會調用zend_do_begin_function_call函數。 在此函數中,當使用到命名空間時會檢查函數名,其調用的函數為zend_resolve_non_class_name。 在zend_resolve_non_class_name函數中會根據類型作出判斷並返回相關結果:
- 完全限定名稱的函數: 程式首先會做此判斷,其判斷的依據是第一個字元是否為"\",這種情況下,在解析時會直接返回。 如類似於\strlen這樣以\開頭的全域調用或類似於前面定義的\tipi\Exception調用。
- 所有的非限定名稱和限定名稱(非完全限定名稱):根據當前的匯入規則 程式判斷是否為別名,並從編譯期間儲存別名的HashTable中取出對應的命名空間名稱,將其與現有的函數名合并。 關於別名的儲存及產生在後面的內容中會說明,
- 在命名空間內部: 所有的沒有根據匯入規則轉換的限定名稱均會在其前面加上當前的命名空間名稱。最後判斷是否在當前命名空間, 最終程式都會返回一個合并了命名空間的函數名。
別名/匯入
允許通過別名引用或匯入外部的完全限定名稱,是命名空間的一個重要特徵。 這有點類似於在類 unix 檔案系統中可以建立對其它的檔案或目錄的符號串連。 PHP 命名空間支援 有兩種使用別名或匯入方式:為類名稱使用別名,或為命名空間名稱使用別名。
PHP不支援匯入函數或常量。
在PHP中,別名是通過操作符 use 來實現的。從而我們可以從源碼中找到編譯時間調用的函數是zend_do_use。 別名在編譯為中間代碼過程中存放在CG(current_import)中,這是一個HashTable。 zend_do_use整個函數的實現基本上是一個尋找,判斷是否錯誤,最後寫入到HashTable的過程。 其中針對命名空間和類名都有匯入的處理過程,而對於常量和函數來說卻沒有, 這就是PHP不支援匯入函數或常量的根本原因所在。
延伸閱讀
此文章所在專題列表如下:
- PHP核心探索:從SAPI介面開始
- PHP核心探索:一次請求的開始與結束
- PHP核心探索:一次請求生命週期
- PHP核心探索:單進程SAPI生命週期
- PHP核心探索:多進程/線程的SAPI生命週期
- PHP核心探索:Zend引擎
- PHP核心探索:再次探討SAPI
- PHP核心探索:Apache模組介紹
- PHP核心探索:通過mod_php5支援PHP
- PHP核心探索:Apache運行與鉤子函數
- PHP核心探索:嵌入式PHP
- PHP核心探索:PHP的FastCGI
- PHP核心探索:如何執行PHP指令碼
- PHP核心探索:PHP指令碼的執行細節
- PHP核心探索:作業碼OpCode
- PHP核心探索:PHP裡的opcode
- PHP核心探索:解譯器的執行過程
- PHP核心探索:變數概述
- PHP核心探索:變數儲存與類型
- PHP核心探索:PHP中的雜湊表
- PHP核心探索:理解Zend裡的雜湊表
- PHP核心探索:PHP雜湊演算法設計
- PHP核心探索:翻譯一篇HashTables文章
- PHP核心探索:雜湊碰撞攻擊是什嗎?
- PHP核心探索:常量的實現
- PHP核心探索:變數的儲存
- PHP核心探索:變數的類型
- PHP核心探索:變數的值操作
- PHP核心探索:變數的建立
- PHP核心探索:預定義變數
- PHP核心探索:變數的檢索
- PHP核心探索:變數的類型轉換
- PHP核心探索:弱類型變數的實現
- PHP核心探索:靜態變數的實現
- PHP核心探索:變數類型提示
- PHP核心探索:變數的生命週期
- PHP核心探索:變數賦值與銷毀
- PHP核心探索:變數範圍
- PHP核心探索:詭異的變數名
- PHP核心探索:變數的value和type儲存
- PHP核心探索:全域變數Global
- PHP核心探索:變數類型的轉換
- PHP核心探索:記憶體管理開篇
- PHP核心探索:Zend記憶體管理器
- PHP核心探索:PHP的記憶體管理
- PHP核心探索:記憶體的申請與銷毀
- PHP核心探索:引用計數與寫時複製
- PHP核心探索:PHP5.3的記憶體回收機制
- PHP核心探索:記憶體管理中的cache
- PHP核心探索:寫時複製COW機制
- PHP核心探索:數組與鏈表
- PHP核心探索:使用雜湊表API
- PHP核心探索:數組操作
- PHP核心探索:數組源碼分析
- PHP核心探索:函數的分類
- PHP核心探索:函數的內部結構
- PHP核心探索:函數結構轉換
- PHP核心探索:定義函數的過程
- PHP核心探索:函數的參數
- PHP核心探索:zend_parse_parameters函數
- PHP核心探索:函數傳回值
- PHP核心探索:形參return value
- PHP核心探索:函數調用與執行
- PHP核心探索:引用與函數執行
- PHP核心探索:匿名函數及閉包
- PHP核心探索:物件導向開篇
- PHP核心探索:類的結構和實現
- PHP核心探索:類的成員變數
- PHP核心探索:類的成員方法
- PHP核心探索:類的原型zend_class_entry
- PHP核心探索:類的定義
- PHP核心探索:存取控制
- PHP核心探索:繼承,多態與抽象類別
- PHP核心探索:魔術函數與延遲綁定
- PHP核心探索:保留類與特殊類
- PHP核心探索:對象
- PHP核心探索:建立對象執行個體
- PHP核心探索:對象屬性讀寫
- PHP核心探索:命名空間
- PHP核心探索:定義介面
- PHP核心探索:繼承與實現介面
- PHP核心探索:資源resource類型
- PHP核心探索:Zend虛擬機器
- PHP核心探索:虛擬機器的詞法解析
- PHP核心探索:虛擬機器的文法分析
- PHP核心探索:中間代碼opcode的執行
- PHP核心探索:代碼的加密與解密
- PHP核心探索:zend_execute的具體執行過程
- PHP核心探索:變數的引用與計數規則
- PHP核心探索:新記憶體回收機制說明
____PHP核心探索:命名空間