(PHP 5 >= 5.3.0, PHP 7, PHP 8)
本文分兩節:常見(jiàn)問(wèn)題、有助于完全理解的實(shí)現詳情。
首先,常見(jiàn)問(wèn)題。
\my\name
和 \name
這樣的名稱(chēng)是如何解析的?
my\name
這樣的名稱(chēng)是如何解析的?
name
這樣的非限定類(lèi)名是如何解析的?
name
這樣的非限定常量和函數名是如何解析的?
為了幫助理解,我們提供了一些命名空間實(shí)現細節。
不需要。命名空間不影響現存的代碼,也不影響即將要寫(xiě)下的不含命名空間的代碼。 想要的話(huà)可以這樣寫(xiě):
示例 #1 在命名空間之外訪(fǎng)問(wèn)全局類(lèi)
<?php
$a = new \stdClass;
以上等同于:
示例 #2 在命名空間之外訪(fǎng)問(wèn)全局類(lèi)
<?php
$a = new stdClass;
示例 #3 在命名空間內訪(fǎng)問(wèn)內置的類(lèi)
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $parameter_type_example = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// 擴展內置或全局的 class
class MyException extends \Exception {}
?>
示例 #4 在命名空間中訪(fǎng)問(wèn)內置的類(lèi)、函數、常量
<?php
namespace foo;
class MyClass {}
// 以當前命名空間中的 class 作為參數的類(lèi)型
function test(MyClass $parameter_type_example = null) {}
// 以當前命名空間中的 class 作為參數的類(lèi)型的另一種方式
function test(\foo\MyClass $parameter_type_example = null) {}
// 在當前命名空間中擴展一個(gè)類(lèi)
class Extended extends MyClass {}
// 訪(fǎng)問(wèn)全局函數
$a = \globalfunc();
// 訪(fǎng)問(wèn)全局常量
$b = \INI_ALL;
?>
\my\name
和 \name
這樣的名稱(chēng)是如何解析的?
以 \
開(kāi)頭的名稱(chēng)總是會(huì )解析成原樣,
因此 \my\name
實(shí)際上是 my\name
,
而 \Exception
是 Exception
。
示例 #5 完全限定名稱(chēng)
<?php
namespace foo;
$a = new \my\name(); // class "my\name" 的實(shí)例
echo \strlen('hi'); // 調用函數 "strlen"
$a = \INI_ALL; // $a 的值設置成常量 "INI_ALL"
?>
my\name
這樣的名稱(chēng)是如何解析的?
像 my\name
這樣包含反斜線(xiàn)的名稱(chēng),但不以反斜線(xiàn)開(kāi)頭的名稱(chēng),
能夠以?xún)煞N不同的方式解析。
如果有個(gè)導入語(yǔ)句,將其他名字設置別名為 my
,
則導入別名會(huì )應用到 my\name
的 my
部分。
如果沒(méi)有導入,就會(huì )追加當前的命名空間名稱(chēng)為 my\name
的前綴。
示例 #6 限定名稱(chēng)
<?php
namespace foo;
use blah\blah as foo;
$a = new my\name(); // class "foo\my\name" 的實(shí)例
foo\bar::name(); // 調用 class "blah\blah\bar" 的靜態(tài)方法 "name"
my\bar(); // 調用函數 "foo\my\bar"
$a = my\BAR; // 設置 $a 的值為 "foo\my\BAR"
?>
name
這樣的非限定名稱(chēng)是如何解析的?
像 name
這樣不包含反斜線(xiàn)的名稱(chēng),
能夠以?xún)煞N不同的方式解析。
如果有導入語(yǔ)句,設置別名為 name
,就會(huì )應用導入別名。
如果沒(méi)有,就會(huì )把當前命名空間添加到 name
的前綴。
示例 #7 非限定類(lèi)名
<?php
namespace foo;
use blah\blah as foo;
$a = new name(); // class "foo\name" 的實(shí)例
foo::name(); // 調用 class "blah\blah" 的靜態(tài)方法 "name"
?>
name
這樣的非限定常量和函數名是如何解析的?
像 name
這樣不包含反斜線(xiàn)的常量和函數名,能以?xún)煞N不同的方式解析。
首先,當前命名空間會(huì )添加到 name
的前綴。
然后,如果當前命名空間不存在函數和常量 name
,
而全局存在,就會(huì )使用全局的函數和常量 name
。
示例 #8 非限定函數和常量名
<?php
namespace foo;
use blah\blah as foo;
const FOO = 1;
function my() {}
function foo() {}
function sort(&$a)
{
sort($a);
$a = array_flip($a);
return $a;
}
my(); // 調用 "foo\my"
$a = strlen('hi'); // 由于 "foo\strlen" 不存在,所以調用全局的 "strlen"
$arr = array(1,3,2);
$b = sort($arr); // 調用函數 "foo\sort"
$c = foo(); // 未導入,調用函數 "foo\foo"
$a = FOO; // 未導入,設置 $a 為常量 "foo\FOO" 的值
$b = INI_ALL; // 設置 $b 為全局常量 "INI_ALL" 的值
?>
允許以下腳本中的組合:
file1.php
<?php
namespace my\stuff;
class MyClass {}
?>
another.php
<?php
namespace another;
class thing {}
?>
file2.php
<?php
namespace my\stuff;
include 'file1.php';
include 'another.php';
use another\thing as MyClass;
$a = new MyClass; // class "thing" 的實(shí)例來(lái)自于命名空間 another
?>
盡管在 my\stuff
命名空間中存在 MyClass
,
因為類(lèi)定義在了獨立的文件中,所以不會(huì )發(fā)生名稱(chēng)沖突。
不過(guò),接下來(lái)的例子中,因為 MyClass 定義在了 use 語(yǔ)句的同一個(gè)文件中,
所以發(fā)生了名稱(chēng)沖突,導致了 fatal 錯誤。
<?php
namespace my\stuff;
use another\thing as MyClass;
class MyClass {} // fatal error: MyClass conflicts with import statement
$a = new MyClass;
?>
PHP 不允許嵌套 namespace
<?php
namespace my\stuff {
namespace nested {
class foo {}
}
}
?>
<?php
namespace my\stuff\nested {
class foo {}
}
?>
重要的是,字符串中反斜線(xiàn)是一個(gè)轉義字符,因此在字符串中使用時(shí),必須要寫(xiě)兩遍。 否則就會(huì )在無(wú)意中造成一些后果:
示例 #9 在雙引號字符串中使用命名空間的危險性
<?php
$a = new "dangerous\name"; // 在雙引號字符串中,\n 是換行符!
$obj = new $a;
$a = new 'not\at\all\dangerous'; // 這里沒(méi)有問(wèn)題
$obj = new $a;
?>
像 FOO
這樣的非限定名稱(chēng)常量,如果使用的時(shí)候還沒(méi)定義,
會(huì )產(chǎn)生一個(gè) notice。PHP 會(huì )假設該常量的值是 FOO
。
如果沒(méi)有找到包含反斜線(xiàn)的常量,無(wú)論是完全或者不完全限定的名稱(chēng),都會(huì )產(chǎn)生 fatal 錯誤。
示例 #10 未定義的常量
<?php
namespace bar;
$a = FOO; // 產(chǎn)生 notice - undefined constants "FOO" assumed "FOO";
$a = \FOO; // fatal error, undefined namespace constant FOO
$a = Bar\FOO; // fatal error, undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO; // fatal error, undefined namespace constant Bar\FOO
?>
在命名空間內定義特殊的內置常量,會(huì )導致 fatal 錯誤
示例 #11 未定義的常量
<?php
namespace bar;
const NULL = 0; // fatal error;
const true = 'stupid'; // 也是 fatal error;
// etc.
?>