项目 | 描述 |
---|---|
搜索引擎 | Bing、Google |
AI 大模型 | 文心一言、通义千问、讯飞星火认知大模型、ChatGPT |
PHP 官方 | PHP Manual |
PHP 官方 | language.namespaces.rationale.php |
PHP 官方 | control-structures.declare.php |
项目 | 描述 |
---|---|
PHP | 5.5.0 、5.6.8 、7.0.0 、7.2.5 、7.4.9 、8.0.0 、8.2.9 |
PHP 编辑器 | PhpStorm 2023.1.1(专业版) |
如何理解 PHP 中的命名空间?PHP 官方文档 对此有一个很好的描述(难得通俗易懂):
什么是命名空间?从广义上来说,命名空间是一种封装事物的方法
。在很多地方都可以见到这种抽象概念。例如
,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子
,文件 foo.txt 可以同时在目录 /home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外
,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到 /home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念
。
在 PHP 中,命名空间 用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题
:
命名冲突
。很长的标识符名称(通常是为了缓解第一类问题而定义的)
创建一个 别名(简短的名称)
的名称,提高源代码的可读性。PHP 对命名空间的支持从 5.3
版本开始,在此前的 PHP 版本中,命名空间机制处于不可用状态。
PHP 中并不是所有组成部分都将受到命名空间的影响。在 PHP 官方文档中 记录了受命名空间影响的类型
,具体如下:
在 PHP 中,全局命名空间是一个 特殊的命名空间
,该命名空间 没有具体的名称
。全局命名空间是 PHP 脚本使用的 默认命名空间
,当你在 PHP 脚本中没有显式地定义命名空间时,所有的类、函数、常量等都处于全局命名空间中。
__NAMESPACE__
是 PHP 提供的一个魔术常量,用于获取当前命名空间的名称
。您可以在任何命名空间内使用魔术常量 __NAMESPACE__
,它将返回 一个包含当前命名空间名称的字符串
。
举个栗子
function func() {
return __NAMESPACE__;
}
var_dump(__NAMESPACE__);
var_dump(func());
执行效果
由于 全局命名空间没有具体的名称
,故在全局命名空间中访问 __NAMESPACE__
常量将获得一个空字符串。
string(0) ""
string(0) ""
在 PHP 中,使用 namespace 关键字用于命名空间的定义
。定义全局命名空间可参考如下示例:
namespace {
# 括号范围内即全局命名空间。
var_dump(__NAMESPACE__);
}
执行效果
string(0) ""
在定义命名空间的过程中,可在 namespace
关键字后指定被定义命名空间的名称。对此,请参考如下示例:
# 定义一个名为 RedHeart 的命名空间
namespace RedHeart {
var_dump(__NAMESPACE__);
}
# 定义一个名为 BinaryMoon\RedHeart 的命名空间
namespace BinaryMoon\RedHeart {
var_dump(__NAMESPACE__);
}
执行效果
string(8) "RedHeart"
string(19) "BinaryMoon\RedHeart"
命名空间的名称 只能包含字母、数字和下划线,并且不能以数字开头
。需要注意的是,命名空间的名称的大小写并不敏感
,\RedHeart
与 \REDHEART
将被视为同一命名空间。对此,请参考如下示例:
namespace RedHeart {
# 名为 RedHeart 的命名空间中定义一个名为 HOME 的常量
const HOME = "BinaryMoon";
}
namespace REDHEART {
# 尝试在名为 REDHEART 的命名空间中对 HOME 常量进行访问
var_dump(HOME);
}
执行效果
在 RedHeart
命名空间中的常量被 REDHEART
命名空间中的语句成功访问,这说明两者为同一命名空间,命名空间的名称是 不区分大小写的
。
string(10) "BinaryMoon"
在 PHP 中,以 PHP
作为名称开头的命名空间通常用于表示 PHP 本身的 核心命名空间
。这些命名空间用于组织 PHP 语言 内置的类、接口、函数和常量
。虽然您可以在自己的代码中创建以 PHP
开头的命名空间,但最好不要这样做,以 避免混淆和冲突
。
在 PHP 中,子命名空间是指在一个已存在的命名空间内创建 更具体或更深层次的命名空间
。子命名空间是一种用于更好组织和分类代码的方式,允许您 在一个已有的命名空间下创建更多的子级命名空间
。子级命名空间与父级命名空间之间使用斜杠 \
进行分隔。对此,请参考如下内容:
namespace RedHeart {
# 创建一个位于全局命名空间下名为 RedHeart 的子命名空间
}
namespace RedHeart\BinaryMoon {
# 创建一个位于 \RedHeart\ 下的子空间
# \RedHeart 前的 \ 表示全局命名空间,在为命名空间命名时不需要添加
# 该符号。否则,PHP 将抛出 Parse error 异常。
}
无括号命名空间声明
使用分号 ;
结束命名空间的声明。当您使用这种方式定义命名空间时,命名空间的影响将持续到文件的结束或下一个命名空间声明
。也就是说,此声明之后的所有代码都将被认为是在这个命名空间内。
有括号命名空间声明
使用大括号 {}
来明确地定义命名空间的范围。在这对大括号内的代码都将被认为是在这个命名空间内
,而大括号外的代码则不在此命名空间内。
在同一 PHP 脚本文件中,有括号命名空间声明与无括号命名空间声明 不能混用
。否则,PHP 将为此抛出 Fatal error
异常并立即停止运行。对此,请参考如下示例:
# 使用无括号命名空间声明
namespace RedHeart;
# 使用有括号命名空间声明
namespace BinaryMoon {
}
执行效果
Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in C:\demo.php on line 8
PHP Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in C:\demo.php on line 8
在 PHP 中定义命名空间的过程中,推荐使用有括号命名空间声明。理由有如下三点:
可以明确指示命名空间的开始和结束
,使代码更易于阅读。仅能够通过有括号命名空间声明这一方式进行声明
,若在 PHP 脚本文件中使用无括号命名空间声明,则 无法声明全局命名空间(有括号命名空间声明与无括号命名空间声明不可混用)
。当您在 PHP 脚本中 声明任意命名空间
后,仅能够在所有命名空间前使用 declare
语句及 PHP 起始标签 。
除此之外,不允许在名称空间范围外使用任何非空白字符
。否则,PHP 将抛出 Fatal error
并立即停止运行。对此,请参考如下示例:
产生 Fatal error 异常
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Namespace</title>
</head>
<body>
<?php
namespace BinaryMoon;
?>
</body>
</html>
正常运行
# declare 的功能不必在意,此处仅仅为了表达
# 仅有 PHP 起始标签与 declare 语句可以出现在所有命名空间之前(之外)。
declare(ticks=1);
namespace BinaryMoon {}
使用有括号命名空间会让人尝试进行命名空间嵌套,但这是不被 PHP 允许的,若您尝试这样做,PHP 将抛出 Fatal Error
异常。对此,请参考如下示例:
namespace RedHeart {
# 尝试在 RedHeart 命名空间内部声明 BinaryMoon 命名空间
namespace BinaryMoon {
}
}
执行效果
PHP Fatal error: Namespace declarations cannot be nested in C:\test.php on line 6