2024年PHP日本会议

使用命名空间:别名/导入

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

能够用别名引用外部全限定名或进行导入是命名空间的一个重要特性。这类似于基于unix的文件系统创建指向文件或目录的符号链接的能力。

PHP可以为常量、函数、类、接口、trait、枚举和命名空间创建别名/导入。

别名是使用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 函数
?>
请注意,对于命名空间名称(包含命名空间分隔符的全限定命名空间名称,例如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声明

从相同的namespace导入的类、函数和常量可以在单个use语句中组合在一起。

<?php

use some\namespace\ClassA;
use
some\namespace\ClassB;
use
some\namespace\ClassC as C;

use function
some\namespace\fn_a;
use function
some\namespace\fn_b;
use function
some\namespace\fn_c;

use const
some\namespace\ConstA;
use const
some\namespace\ConstB;
use const
some\namespace\ConstC;

// 等效于以下分组的 use 声明
use some\namespace\{ClassA, ClassB, ClassC as C};
use function
some\namespace\{fn_a, fn_b, fn_c};
use const
some\namespace\{ConstA, ConstB, ConstC};
添加笔记

用户贡献笔记 17条笔记

dominic_mayers at yahoo dot com
8年前
关键字“use”已被用于三种不同的应用场景
1- 在命名空间中导入/别名类、trait、常量等,
2- 在类中插入 trait,
3- 在闭包中继承变量。
此页面仅关于第一个应用:导入/别名。trait可以插入到类中,但这与在命名空间中导入trait不同,后者不能在块作用域中完成,如示例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 对象

/*********************************************/
Chinese translation is incorrect.
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
The correct sentence should be:
// 如果不使用 "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 的示例。

<?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