關於命名空間namespace
- 雖然任意合法的PHP代碼都可以包含在命名空間中,但只有以下類型的代碼受命名空間的影響,它們是:類(包括抽象類和traits)、接口、函數和常量。
在聲明命名空間之前唯一合法的代碼是用於定義源文件編碼方式的 declare 語句。另外,所有非 PHP 代碼包括空白符都不能出現在命名空間的聲明之前:
<html>
<?php
namespace MyProject; // 命名空間前出現了“<html>” 會致命錯誤
- 命名空間必須是程序腳本的第一條語句
?>
- 允許通過別名引用或導入外部的完全限定名稱,是命名空間的一個重要特征。這有點類似於在類 unix 文件系統中可以創建對其它的文件或目錄的符號連接。
所有支持命名空間的PHP版本支持三種別名或導入方式:為類名稱使用別名、為接口使用別名或為命名空間名稱使用別名。PHP 5.6開始允許導入函數或常量或者為它們設置別名。在PHP中,別名是通過操作符 use 來實現的.
- 使用命名空間:別名/導入
PHP 命名空間支持 有兩種使用別名或導入方式:為類名稱使用別名,或為命名空間名稱使用別名。
在PHP中,別名是通過操作符 use 來實現的. 下面是一個使用所有可能的三種導入方式的例子:
1、使用use操作符導入/使用別名
<?php
namespace foo;
use
My\Full\Classname as Another;
// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 導入一個全局類
use \ArrayObject;
$obj = new namespace\Another; // 實例化 foo\Another 對象
$obj = new Another; // 實例化 My\Full\Classname 對象
NSname\subns\func(); // 調用函數 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); //
實例化 ArrayObject 對象
// 如果不使用 "use \ArrayObject" ,則實例化一個 foo\ArrayObject 對象
?>
- 全局空間
如果沒有定義任何命名空間,所有的類與函數的定義都是在全局空間,與 PHP 引入命名空間概念前一樣。
在名稱前加上前綴 \ 表示該名稱是全局空間中的名稱,即使該名稱位於其它的命名空間中時也是如此。
使用全局空間說明
<?php
namespace A\B\C;
/* 這個函數是 A\B\C\fopen */
function fopen() {
/* ...
*/
$f = \fopen(...); //
調用全局的fopen函數
return $f;
}
?>
- 使用命名空間:後備全局函數/常量
在一個命名空間中,當 PHP 遇到一個非限定的類、函數或常量名稱時,它使用不同的優先策略來解析該名稱。
類名稱總是解析到當前命名空間中的名稱。因此在訪問系統內部或不包含在命名空間中的類名稱時,必須使用完全限定名稱,例如:
1、在命名空間中訪問全局類
<?php
namespace A\B\C;
class
Exception extends \Exception {}
$a
= new Exception(‘hi‘); // $a 是類 A\B\C\Exception 的一個對象
$b = new
\Exception(‘hi‘); //
$b 是類 Exception 的一個對象
$c
= new ArrayObject; // 致命錯誤, 找不到
A\B\C\ArrayObject 類
?>
對於函數和常量來說,如果當前命名空間中不存在該函數或常量,PHP 會退而使用全局空間中的函數或常量。
2、 命名空間中後備的全局函數/常量
<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
return \strlen($str) - 1;
}
echo
E_ERROR, "\n"; // 輸出 "45"
echo INI_ALL, "\n"; // 輸出 "7" - 使用全局常量 INI_ALL
echo
strlen(‘hi‘), "\n"; // 輸出 "1"
if
(is_array(‘hi‘)) { // 輸出 "is not array"
echo "is array\n";
}
else {
echo "is not array\n";
}
?>
- 名稱解析遵循下列規則:
- 對完全限定名稱的函數,類和常量的調用在編譯時解析。例如 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() 的調用是這樣解析的:
- 在當前命名空間中查找名為 A\B\foo() 的函數
- 嘗試查找並調用 全局(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()。
- 子命名空間
與目錄和文件的關系很象,PHP 命名空間也允許指定層次化的命名空間的名稱。因此,命名空間的名字可以使用分層次的方式定義:
<?php
namespace MyProject\Sub\Level;
//聲明分層次的單個命名空間
const CONNECT_OK =
1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>
上面的例子創建了常量 MyProject\Sub\Level\CONNECT_OK,類 MyProject\Sub\Level\Connection 和函數 MyProject\Sub\Level\Connect。
Static 關鍵字
聲明類屬性或方法為 static(靜態),就可以不實例化類而直接訪問。
靜態屬性不能通過一個類已實例化的對象來訪問,
(但靜態方法可以)。
由於靜態方法不需要通過對象即可調用,所以偽變量 $this 在靜態方法中不可用。
靜態屬性不可以由對象通過 -> 操作符來訪問。
就我們以往的經驗來說,類中的方法往往都是由已實例化的對象來調用的,因此常常用偽變量$this表示調用此方法的已實例化的對象。
用$this->var或者$this->function的形式來訪問該對象的方法或屬性。
那麽這裏
聲明類屬性或方法為 static(靜態),就可以不實例化類而直接訪問。
public static function staticimage($center)
public function map(){
return \Map::staticimage(‘北京昌平沙河地鐵‘);
}
就像這裏可以直接在Index/map中直接調用extend/Map.php中的靜態方法。
自 PHP 5.3.0 起,可以用一個變量來動態調用類。但該變量的值不能為關鍵字 self,parent 或 static。
<?php
class Foo {
public static $my_static = ‘foo‘;
public function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . PHP_EOL;
$foo = new Foo();
print $foo->staticValue() .
PHP_EOL;
?>
執行以上程序,輸出結果為:
foo
foo
關於命名空間namespace