PHP命名空間
PHP 命名空間(namespace)是在PHP 5.3中加入的瞭亮。
PHP 命名空間可以解決以下兩類問題:
- 用戶編寫的代碼與PHP內(nèi)部的類/函數(shù)/常量或第三方類/函數(shù)/常量之間的名字沖突县爬。
- 為很長的標(biāo)識符名稱(通常是為了緩解第一類問題而定義的)創(chuàng)建一個別名(或簡短)的名稱晌坤,提高源代碼的可讀性敦冬。
定義命名空間
默認(rèn)情況下庶喜,所有常量、類和函數(shù)名都放在全局空間下揍庄,就和PHP支持命名空間之前一樣咆蒿。
命名空間通過關(guān)鍵字namespace
來聲明。如果一個文件中包含命名空間蚂子,它必須在其它所有代碼之前聲明命名空間沃测。語法格式如下:
<?php
// 定義代碼在 'MyProject' 命名空間中
namespace MyProject;
// ... 代碼 ...
?>
也可以在同一個文件中定義不同的命名空間代碼,如:
<?php
namespace MyProject;
const CONNECT_OK = 1; //命名空間對const變量管用
class Connection { /* ... */ } //對類管用
function connect() { /* ... */ } //同樣對函數(shù)管用
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
但是食茎,命名空間對define
定義的常量不管用:
<?php
namespace one;
define('value1', 'value2');
namespace two;
define('value1', 'value3');
?>
就會報(bào)錯:
Notice: Constant value1 already defined in A:\myphp_www\PHPTutorial\WWW\tp5\test.php on line 19
- 注意事項(xiàng):
- 聲明命名空間之前唯一合法的代碼是用于定義源文件編碼方式的
declare
語句蒂破。所有非 PHP 代碼包括空白符都不能出現(xiàn)在命名空間的聲明之前。
<?php
declare(encoding='UTF-8'); //定義多個命名空間和不包含在命名空間中的代碼
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代碼
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
以下代碼會出現(xiàn)語法錯誤:
<html>
<?php
namespace MyProject; // 命名空間前出現(xiàn)了“<html>” 會致命錯誤 - 命名空間必須是程序腳本的第一條語句
?>
就會出現(xiàn)致命錯誤:
Fatal error: Namespace declaration statement has to be the very first statement in the script in
A:\myphp_www\PHPTutorial\WWW\tp5\test.php on line 23
- 將全局的非命名空間中的代碼與命名空間中的代碼組合在一起别渔,只能使用大括號形式的語法附迷。全局代碼必須用一個不帶名稱的
namespace
語句加上大括號括起來。
<?php
namespace MyProject { //命名空間代碼
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代碼
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
子命名空間
與目錄和文件的關(guān)系很像哎媚,PHP 命名空間也允許指定層次化的命名空間的名稱喇伯。因此,命名空間的名字可以使用分層次的方式定義:
<?php
namespace MyProject\Sub\Level; //聲明分層次的單個命名空間
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>
上面的例子創(chuàng)建了常量MyProject\Sub\Level\CONNECT_OK
拨与,類 MyProject\Sub\Level\Connection
和函數(shù) MyProject\Sub\Level\Connect
稻据。
命名空間使用
PHP 命名空間中的類名可以通過三種方式引用:
非限定名稱,或不包含前綴的類名稱买喧,即訪問的是當(dāng)前命名空間里的內(nèi)容捻悯。例如
$a=new foo();
或foo::staticmethod();
匆赃。如果當(dāng)前命名空間是currentnamespace
,foo
將被解析為currentnamespace\foo
今缚。如果使用foo
的代碼是全局的算柳,不包含在任何命名空間中的代碼,則foo
會被解析為foo
荚斯。 警告:如果命名空間中的函數(shù)或常量未定義埠居,則該非限定的函數(shù)名稱或常量名稱會被解析為全局函數(shù)名稱或常量名稱。限定名稱事期,或包含前綴的名稱滥壕,以當(dāng)前命名空間所處的路徑為相對路徑,繼續(xù)向下尋找指定的命名空間兽泣,類似于文件相對路徑绎橘。例如
$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
總是被解析為代碼中的文字名(literal name)currentnamespace\foo
。
- file1.php
<?php
namespace Foo\Bar\subnamespace; //子命名空間
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
- file2.php
<?php
namespace Foo\Bar;
include 'file1.php';//引入file.php文件
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* 非限定名稱 */
foo(); // 解析為函數(shù) Foo\Bar\foo
foo::staticmethod(); // 解析為類 Foo\Bar\foo 亚皂,方法為 staticmethod
echo FOO; // 解析為常量 Foo\Bar\FOO
/* 限定名稱 */
subnamespace\foo(); // 解析為函數(shù) Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析為類 Foo\Bar\subnamespace\foo,
// 以及類的方法 staticmethod
echo subnamespace\FOO; // 解析為常量 Foo\Bar\subnamespace\FOO
/* 完全限定名稱 */
\Foo\Bar\foo(); // 解析為函數(shù) Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析為類 Foo\Bar\foo, 以及類的方法 staticmethod
echo \Foo\Bar\FOO; // 解析為常量 Foo\Bar\FOO
?>
注意:訪問任意全局類俱箱、函數(shù)或常量,都可以使用完全限定名稱灭必,例如 \strlen()
或 \Exception
或 \INI_ALL
狞谱。
在命名空間內(nèi)部訪問全局類、函數(shù)和常量:
<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // 調(diào)用全局函數(shù)strlen
$b = \INI_ALL; // 訪問全局常量 INI_ALL
$c = new \Exception('error'); // 實(shí)例化全局類 Exception
?>
引入空間成員
use
空間名\空間名 【as
別名】:將指定空間引入到當(dāng)前空間禁漓。同可以使用as關(guān)鍵字為被引入的空間起個別名跟衅。use
空間名\空間名\成員類 【as
別名】:將指定的空間中的成員引入到當(dāng)前空間,引入空間成員只能引入類璃饱。
<?php
namespace foo;
use My\Full\Classname as Another;
// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 導(dǎo)入一個全局類
use \ArrayObject;
$obj = new namespace\Another; // 實(shí)例化 foo\Another 對象
$obj = new Another; // 實(shí)例化 My\Full\Classname 對象
NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 實(shí)例化 ArrayObject 對象
// 如果不使用 "use \ArrayObject" 与斤,則實(shí)例化一個 foo\ArrayObject 對象
?>
一行包含多個use語句情況:
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 實(shí)例化 My\Full\Classname 對象
NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func
?>
導(dǎo)入操作是在編譯執(zhí)行的肪康,但動態(tài)的類名稱荚恶、函數(shù)名稱或常量名稱則不是撩穿。
- 導(dǎo)入和動態(tài)名稱
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 實(shí)例化一個 My\Full\Classname 對象
$a = 'Another';
$obj = new $a; // 實(shí)際化一個 Another 對象
?>
另外,導(dǎo)入操作只影響非限定名稱和限定名稱谒撼。完全限定名稱由于是確定的食寡,故不受導(dǎo)入的影響。
- 導(dǎo)入和完全限定名稱
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 實(shí)例化 My\Full\Classname 類
$obj = new \Another; // 實(shí)例化 Another 類
$obj = new Another\thing; // 實(shí)例化 My\Full\Classname\thing 類
$obj = new \Another\thing; // 實(shí)例化 Another\thing 類
?>
PHP公共空間
可以簡單的理解廓潜,沒有定義命名空間的方法(函數(shù))抵皱、類庫(class)、屬性(變量)都默認(rèn)歸屬于公共空間辩蛋。這樣就解釋了為php5.3.0以前版本書寫的代碼大部分為何在php5.3.0及其以上版本還能正常運(yùn)行的原因呻畸。
另外:公共空間中的代碼段被引入到某個命名空間下后,該公共空間中的代碼段不屬于任何命名空間悼院!
- 1.php
<?php
function fun(){
}
class Demo{
}
?>
- 2.php
<?php
namespace cn\my;
include 'common.php'; //引入當(dāng)前目錄下的文件
$demo = new Demo; //出現(xiàn)致命錯誤:找不到 cn\my\Demo類
$demo = new \Demo(); //正確的方式 加上 \
var_dump(); // 錯誤伤为,系統(tǒng)函數(shù)在公共空間
\var_dump(); // 正確,使用了 \
?>
說明:調(diào)用公共空間的方式是直接在元素名稱前面加上 \
就可以了据途,否則 PHP 解析器會認(rèn)為用戶像調(diào)用當(dāng)前空間下的元素绞愚。除了自定義的元素,還包括 PHP 自帶的元素颖医,都屬于公共空間位衩。其實(shí)公共空間的函數(shù)和常量不用加\
也可以正常調(diào)用,但是為了正確區(qū)分元素所在區(qū)域熔萧,還是建議調(diào)用函數(shù)的時候加上\
糖驴。