PHP Conference Japan 2024

使用命名空間:別名/匯入

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

使用別名或匯入來參考外部完整限定名稱的能力是命名空間的一項重要功能。這類似於基於 Unix 的檔案系統建立檔案或目錄的符號連結的能力。

PHP 可以為常數、函式、類別、介面、特性 (Traits)、列舉 (Enums) 和命名空間建立別名(/匯入)。

別名是使用 use 運算子來完成的。以下範例顯示了所有 5 種匯入方式

範例 #1 使用 use 運算子匯入/建立別名

<?php
namespace foo;
use
My\Full\Classname as Another;

// 這與 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 導入全域類別
use ArrayObject;

// 導入函式
use function My\Full\functionName;

// 函式別名
use function My\Full\functionName as func;

// 導入常數
use const My\Full\CONSTANT;

$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 類別的物件
func(); // 呼叫 My\Full\functionName 函式
echo CONSTANT; // 顯示 My\Full\CONSTANT 的值
?>
請注意,對於命名空間名稱(包含命名空間分隔符號的完整限定命名空間名稱,例如 Foo\Bar,而不是不包含命名空間分隔符號的全域名稱,例如 FooBar),開頭的反斜線是不必要的,也不建議使用,因為導入名稱必須是完整限定的,並且不會相對於目前的命名空間進行處理。

PHP 還支援一個便捷的捷徑,可以將多個 use 陳述式放在同一行。

範例 #2 使用 use 運算子導入/設定別名,多個 use 陳述式合併

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 建立 My\Full\Classname 類別的物件
NSname\subns\func(); // 呼叫 My\Full\NSname\subns\func 函式
?>

導入是在編譯時執行的,因此不會影響動態的類別、函式或常數名稱。

範例 #3 導入和動態名稱

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 建立 My\Full\Classname 類別的物件
$a = 'Another';
$obj = new $a; // 建立 Another 類別的物件
?>

此外,導入只影響非限定名稱和限定名稱。完全限定名稱是絕對的,不受導入影響。

範例 #4 導入和完全限定名稱

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 建立 My\Full\Classname 類別的物件
$obj = new \Another; // 建立 Another 類別的物件
$obj = new Another\thing; // 建立 My\Full\Classname\thing 類別的物件
$obj = new \Another\thing; // 建立 Another\thing 類別的物件
?>

導入的作用域規則

use 關鍵字必須在檔案的最外層作用域(全域作用域)或命名空間宣告內部宣告。這是因為導入是在編譯時完成的,而不是執行時,所以它不能是區塊作用域。以下範例將顯示 use 關鍵字的非法用法

範例 #5 非法導入規則

<?php
namespace Languages;

function
toGreenlandic()
{
use
Languages\Danish;

// ...
}
?>

注意事項:

導入規則是基於每個檔案的,這意味著被引入的檔案將*不會*繼承父檔案的導入規則。

群組 use 宣告

從同一個 命名空間 導入的類別、函式和常數可以在單個 use 陳述式中組合在一起。

<?php

使用 some\namespace\ClassA;
使用
some\namespace\ClassB;
使用
some\namespace\ClassC 作為 C;

使用函式
some\namespace\fn_a;
使用函式
some\namespace\fn_b;
使用函式
some\namespace\fn_c;

使用常數
some\namespace\ConstA;
使用常數
some\namespace\ConstB;
使用常數
some\namespace\ConstC;

// 等同於以下的群組使用宣告
使用 some\namespace\{ClassA, ClassB, ClassC 作為 C};
使用函式
some\namespace\{fn_a, fn_b, fn_c};
使用常數
some\namespace\{ConstA, ConstB, ConstC};
新增註解

使用者貢獻的註解 17 則註解

dominic_mayers at yahoo dot com
8 年前
關鍵字「use」已被用於三個不同的應用:
1- 在命名空間中導入/別名類別、特性、常數等,
2- 在類別中插入特性,
3- 在閉包中繼承變數。
此頁面僅關於第一個應用:導入/別名。特性可以插入到類別中,但這與在命名空間中導入特性不同,如範例 5 所述,這不能在區塊範圍內完成。這可能會造成混淆,尤其是在搜尋關鍵字「use」的所有結果都導向此處關於導入/別名的說明文件時。
匿名
10 年前
<?php use ?> 陳述式不會載入類別檔案。您必須使用 <?php require ?> 陳述式或使用自動載入函式來執行此操作。
Mawia HL
7 年前
這裡提供一個方便的方法,可以使用單個 use 關鍵字導入類別、函式和常數。

<?php
use Mizo\Web\ {
Php\WebSite,
Php\KeyWord,
Php\UnicodePrint,
JS\JavaScript,
function
JS\printTotal,
function
JS\printList,
const
JS\BUAIKUM,
const
JS\MAUTAM
};
?>
k at webnfo dot com
11 年前
請注意,您不能為全域命名空間設定別名。

use \ as test;

echo test\strlen('');

將無法運作。
xzero at elite7hackers dot net
7 年前
我找不到這個問題的答案,所以我自行測試了一下。
我認為這點值得注意

<?php
use ExistingNamespace\NonExsistingClass;
use
ExistingNamespace\NonExsistingClass as whatever;
use
NonExistingNamespace\NonExsistingClass;
use
NonExistingNamespace\NonExsistingClass as whatever;
?>

以上程式碼都不會造成錯誤,除非您真的嘗試使用您導入的類別。

<?php
// 而這段程式碼會因為不存在的類別而產生標準的 PHP 錯誤。
use ExistingNamespace\NonExsistingClass as whatever;
$whatever = new whatever();
?>
me at ruslanbes dot com
8 年前
請注意,程式碼 `use ns1\c1` 可以指從命名空間 `ns1` 導入類別 `c1`,也可以指導入整個命名空間 `ns1\c1`,甚至可以在同一行中同時導入兩者。範例:

<?php
namespace ns1;

class
c1{}

namespace
ns1\c1;

class
c11{}

namespace
main;

use
ns1\c1;

$c1 = new c1();
$c11 = new c1\c11();

var_dump($c1); // object(ns1\c1)#1 (0) { }
var_dump($c11); // object(ns1\c1\c11)#2 (0) { }
c dot 1 at smithies dot org
13 年前
如果您在 CLI 測試程式碼,請注意命名空間別名無法運作!

(在我繼續之前,此範例中的所有反斜線都已更改為百分號,因為我無法在貼文預覽中顯示合理的結果。請在接下來的內容中將所有百分號理解為反斜線。)

假設您有一個要在 myclass.php 中測試的類別

<?php
namespace my%space;
class
myclass {
// ...
}
?>

接著您進入 CLI 進行測試。您可能會認為這樣應該可行,因為您是一行一行輸入的

require 'myclass.php';
use my%space%myclass; // 應該將 'myclass' 設定為 'my%space%myclass' 的別名
$x = new myclass; // 致命錯誤

我認為這是因為別名只在編譯時期解析,而 CLI 只是單純地評估敘述;因此 use 敘述在 CLI 中無效。

如果您將測試程式碼放入 test.php
<?php
require 'myclass.php';
use
my%space%myclass;
$x = new myclass;
//...
?>
它會正常運作。

我希望這樣可以減少未老先禿的人數。
x at d dot a dot r dot k dot REMOVEDOTSANDTHIS dot gray dot org
11 年前
您可以多次「使用」相同的資源,只要每次使用時都以不同的別名導入即可。

例如

<?php
use Lend;
use
Lend\l1;
use
Lend\l1 as l3;
use
Lend\l2;
use
Lend\l1\Keller;
use
Lend\l1\Keller as Stellar;
use
Lend\l1\Keller as Zellar;
use
Lend\l2\Keller as Dellar;

...

?>

在上面的例子中,「Keller」、「Stellar」和「Zellar」都是「\Lend\l1\Keller」的參考,如同「Lend\l1\Keller」、「l1\Keller」和「l3\Keller」。
cl
11 年前
有一點並非顯而易見,尤其是在 PHP 5.3 中,那就是導入語句中的命名空間解析並非遞迴解析。也就是說:如果您為一個導入設定別名,然後在另一個導入中使用該別名,則後者的導入將不會以前者的導入完全解析。

例如
use \Controllers as C;
use C\First;
use C\Last;

First 和 Last 命名空間都不會如預期般解析為 \Controllers\First 或 \Controllers\Last。
ultimater at gmail dot com
8 年前
請注意,「use」導入/別名只適用於目前的命名空間區塊。

<?php

namespace SuperCoolLibrary
{
class
Meta
{
static public function
getVersion()
{
return
'2.7.1';
}
}
}

namespace
{
use
SuperCoolLibrary\Meta;
echo
Meta::getVersion();//輸出 2.7.1
}

namespace
{
echo
Meta::getVersion();//致命錯誤
}

?>

要獲得預期的行為,您應該使用
class_alias('SuperCoolLibrary\Meta','Meta');
ZhangLiang
7 年前
中文翻譯有誤
// 如果不使用 "use \ArrayObject" ,則實例化一個 foo\ArrayObject 對象
應該改成
// 如果不使用 "use ArrayObject" ,則實例化一個 foo\ArrayObject 對象

/*********************************************/
中文說明翻譯有錯誤
// 如果不使用 "use \ArrayObject" ,則實例化一個 foo\ArrayObject 對象
這句話應該修正為
// 如果不使用 "use ArrayObject" ,則實例化一個 foo\ArrayObject 對象
eithed at google mail
3 年前
請記住,命名空間的別名設定是完全可行的,例如:

<?php
use A\B\C\D\E\User;

new
User();
?>

也可以寫成

<?php
use A\B\C\D\E as ENamespace;

new
ENamespace\User();
?>

然而,以下寫法將無法運作

<?php
use A\B\C\D\E as ENamespace;
use
ENamespace\User;

new
User();
?>

> PHP 錯誤:找不到類別 "ENamespace\User"
thinice at gmail.com
14 年前
因為引入動作發生在編譯時期,所以在條件式中嵌入 use 關鍵字無法實現多型。

例如:

<?php
if ($objType == 'canine') {
use
Animal\Canine as Beast;
}
if (
$objType == 'bovine') {
use
Animal\Bovine as Beast;
}

$oBeast = new Beast;
$oBeast->feed();
?>
dominic_mayers at yahoo dot com
8 年前
為了釐清在類別中插入 Trait 和在命名空間中引入 Trait 的區別,以下範例先引入 Trait,然後再插入 Trait。

<?php
namespace ns1;
trait
T {
static
$a = "In T";
}

namespace
ns2;
use
ns1\T; // 在命名空間 ns2 中引入 Trait ns1\T 的名稱
class C {
use
T; // 在類別 C 中插入 Trait T,使用已引入的名稱。
}

namespace
main;
use
ns2\C;
echo
C::$a; // In T;
kelerest123 at gmail dot com
9 年前
關於第五個範例(範例 #5)

在區塊作用域中使用 use 關鍵字並非非法,因為它是用於與 Trait 共享內容。
info at ensostudio dot ru
4 年前
注意:您可以引入不存在的項目而不會產生錯誤
<?php
use UndefinedClass;
use function
undefined_fn;
use const
UNDEFINED_CONST;
?>
但你無法使用/呼叫它們
<?php
$new UndefinedClass
; // 錯誤:使用了未定義的類別
use function undefined_fn; // 錯誤:使用了未定義的函式
use const UNDEFINED_CONST; // 錯誤:使用了未定義的常數
?>
tuxedobob
2 年前
請注意,因為這是在編譯時期處理的,所以在互動模式下執行 PHP 時無法運作。`use` 指令不會拋出錯誤,但它們也不會執行任何動作。
To Top