程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> PHP 面向對象程序設計(oop)學習筆記 (五) - PHP 命名空間

PHP 面向對象程序設計(oop)學習筆記 (五) - PHP 命名空間

編輯:PHP綜合

命名空間概述

在PHP中,命名空間用來解決在編寫類庫或應用程序時創建可重用的代碼如類或函數時碰到的兩類問題:

用戶編寫的代碼與PHP內部的類/函數/常量或第三方類/函數/常量之間的名字沖突。
為很長的標識符名稱(通常是為了緩解第一類問題而定義的)創建一個別名(或簡短)的名稱,提高源代碼的可讀性。
PHP 命名空間提供了一種將相關的類、函數和常量組合到一起的途徑。下面是一個說明 PHP 命名空間語法的示例:

定義命名空間

雖然任意合法的PHP代碼都可以包含在命名空間中,但只有三種類型的代碼受命名空間的影響,它們是:類,函數和常量。命名空間通過關鍵字namespace 來聲明。如果一個文件中包含命名空間,它必須在其它所有代碼之前聲明命名空間。另外,與PHP其它的語言特征不同,同一個命名空間可以定義在多個文件中,即允許將同一個命名空間的內容分割存放在不同的文件中。當然你也可以在同一個文件中定義多個命名空間。

復制代碼 代碼如下:
namespace MyProject;
class MyClass
{
    #code...
}

定義子命名空間:與目錄和文件的關系很象,PHP 命名空間也允許指定層次化的命名空間的名稱。因此,命名空間的名字可以使用分層次的方式定義:

復制代碼 代碼如下:
namespace MyProject\helper\http;
class MyClass
{
    #code...
}

在同一個文件中定義多個命名空間:在同一個文件中聲明多個命名空間有兩種方式,不過在實際編程實踐中,非常不提倡在同一個文件中定義多戈命名空間。這種方式的主要用於將多個 PHP 腳本合並在同一個文件中。下面列出第一種方法。

復制代碼 代碼如下:
namespace MyProject\helper\http;
class MyClass
{
    #code...
}
namespace MyProject\helper\request;
class MyClass
{
    #code...
}

不過強烈不建議使用這種方法,可以參考下面的大括號定義法:

復制代碼 代碼如下:
namespace MyProject\helper\http;
{
    class MyClass
    {
        #code...
    }
}
namespace MyProject\helper\request;
{
    class MyClass
    {
        #code...
    }
}

PHP 命名空間中的元素使用

在討論如何使用命名空間之前,必須了解 PHP 是如何知道要使用哪一個命名空間中的元素的。類名可以通過三種方式引用:

非限定名稱,或不包含前綴的類名稱,例如 $a=new foo(); 或 foo::staticmethod();。如果當前命名空間是 currentnamespace,foo 將被解析為 currentnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,則 foo 會被解析為foo。 警告:如果命名空間中的函數或常量未定義,則該非限定的函數名稱或常量名稱會被解析為全局函數名稱或常量名稱。詳情參見 使用命名空間:後備全局函數名稱/常量名稱。

限定名稱,或包含前綴的名稱,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果當前的命名空間是 currentnamespace,則 foo 會被解析為 currentnamespace\subnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,foo 會被解析為subnamespace\foo。

完全限定名稱,或包含了全局前綴操作符的名稱,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在這種情況下,foo 總是被解析為代碼中的文字名(literal name)currentnamespace\foo。
使用命名空間:別名/導入

允許通過別名引用或導入外部的完全限定名稱,是命名空間的一個重要特征。PHP 命名空間支持 有兩種使用別名或導入方式:為類名稱使用別名,或為命名空間名稱使用別名。在PHP中,別名是通過操作符 use 來實現的。

注意PHP不支持導入函數或常量。

復制代碼 代碼如下:
namespace foo;
use My\Full\Classname as Another;

// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 導入一個全局類
use \ArrayObject;

名稱解析規則

在說明名稱解析規則之前,我們先看一些重要的定義:

非限定名稱Unqualified name:名稱中不包含命名空間分隔符的標識符,例如 Foo
限定名稱Qualified name:名稱中含有命名空間分隔符的標識符,例如 Foo\Bar
完全限定名稱Fully qualified name:名稱中包含命名空間分隔符,並以命名空間分隔符開始的標識符,例如 \Foo\Bar。 namespace\Foo 也是一個完全限定名稱。
名稱解析遵循下列規則:

對完全限定名稱的函數,類和常量的調用在編譯時解析。例如 new \A\B 解析為類 A\B。
所有的非限定名稱和限定名稱(非完全限定名稱)根據當前的導入規則在編譯時進行轉換。例如,如果命名空間 A\B\C 被導入為 C,那麼對 C\D\e() 的調用就會被轉換為 A\B\C\D\e()。
在命名空間內部,所有的沒有根據導入規則轉換的限定名稱均會在其前面加上當前的命名空間名稱。例如,在命名空間 A\B 內部調用 C\D\e(),則 C\D\e() 會被轉換為 A\B\C\D\e() 。
非限定類名根據當前的導入規則在編譯時轉換(用全名代替短的導入名稱)。例如,如果命名空間 A\B\C 導入為C,則 new C() 被轉換為 new A\B\C() 。
在命名空間內部(例如A\B),對非限定名稱的函數調用是在運行時解析的。例如對函數 foo() 的調用是這樣解析的:
1) 在當前命名空間中查找名為 A\B\foo() 的函數
2) 嘗試查找並調用 全局(global) 空間中的函數 foo()。
在命名空間(例如A\B)內部對非限定名稱或限定名稱類(非完全限定名稱)的調用是在運行時解析的。下面是調用 new C() 及 new D\E() 的解析過程: new C()的解析:
在當前命名空間中查找A\B\C類。
嘗試自動裝載類A\B\C。

new D\E()的解析:
在類名稱前面加上當前命名空間名稱變成:A\B\D\E,然後查找該類。
嘗試自動裝載類 A\B\D\E。

為了引用全局命名空間中的全局類,必須使用完全限定名稱 new \C()。

Example 名稱解析示例

復制代碼 代碼如下:
<?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"
?>

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved