目录启示:PHP 中 命名空间及其成员的访问

文章目录

  • 参考
  • 环境
  • 命名空间的使用
      • 全局命名空间成员
      • 子命名空间成员
  • namespace 关键字
      • namespace 的两大功能
      • 使用 namespace\ 访问当前命名空间下的元素
  • 未雨绸缪
      • 第一深情
      • 向上突围
  • (完全)限定名称下的未定义常量
      • PHP8 以下
      • PHP8 及以上
      • 任何情况下的(完全)限定名称下的未定义常量

参考

项目 描述
搜索引擎 BingGoogle
AI 大模型 文心一言通义千问讯飞星火认知大模型ChatGPT
PHP 官方 PHP Manual
PHP 官方 language.namespaces.rationale.php

环境

项目 描述
PHP 5.5.05.6.87.0.07.2.57.4.98.0.08.2.9
PHP 编辑器 PhpStorm 2023.1.1(专业版)

命名空间的使用

全局命名空间成员

全局命名空间成员是指位于 PHP 全局命名空间下的 接口函数常量。全局命名空间是 PHP 脚本的默认命名空间,也被称为 根命名空间




# 定义全局命名空间成员 MyClass、CONSTANT 以及 func。
class MyClass {}
const CONSTANT = "";
function func() {}

在上述示例中,我们定义了全局命名空间成员 \MyClass\CONSTANT 以及 \func。其中,\ 指代全局命名空间。在全局命名空间中访问全局命名空间成员可以不添加 \ 前缀,但在其他命名空间中对全局命名空间成员进行访问则 推荐使用前缀,否则很可能将 使用当前命名空间下的同名成 员。对此,请参考如下示例:




# 全局命名空间
namespace {
    const HOME = 'BinaryMoon';
}

# 命名空间 \RedHeart
namespace RedHeart {
    const HOME = 'China';

    # 尝试访问常量 HOME
    var_dump(HOME);
    var_dump(\HOME);
}

执行效果

string(5) "China"
string(10) "BinaryMoon"

HOME 在命名空间 RedHeart 中的 完全限定名称(可以将其理解为绝对路径)\RedHeart\HOME,在使用 接口函数常量 这些受命名空间影响的组份时,若没有对名称进行 限定(可以理解为相对路径中的一种,相对当前目录进行文件的访问),则将视该名称为当前命名空间成员所属。
由于 HOME 属于未限定名称,故其被解析为 \RedHeart\HOME,而 \HOME 属于完全限定名称,故将使用全局命名空间下的 HOME 常量。

子命名空间成员

声明命名空间时,命名空间所使用的名称均是相对于全局命名空间进行命名的。而在 访问命名空间成员时,则存在三种名称,这三种名称分别可与 类 Unix(如 Linux) 系统中的绝对路径、相对路径相对应。具体如下:

  1. 完全限定名称
    完全限定名称表明了从全局命名空间到目标命名空间所经历的一系列命名空间,如 \HOME\RedHeart\BinaryMoon 就是一个完全限定名称。完全限定名称可与 类 Unix 系统中的绝对路径进行类比。
  2. 限定名称
    限定名称表明了从当前命名空间到目标命名空间所经历的一系列命名空间,如在 \HOME 命名空间中使用的 RedHeart\BinaryMoon 就是一个限定名称,其完全限定名称为 \HOME\RedHeart\BinaryMoon。限定名称可与 类 Unix 系统中的相对路径进行类比。
  3. 非限定名称
    非限定名称仅仅使用单个命名空间名称表示需要访问的命名空间,如在 \HOME 命名空间中使用的 RedHeart 就是一个非限定名称,其完全限定名称为 \HOME\RedHeart。非限定名称同样可与 类 Unix 系统中的相对路径进行类比。



namespace HOME\RedHeart {
    function saySelf() {
        # 通过魔术常量 __NAMESPACE 回当前所属的命名空间名称
        return __NAMESPACE__;
    }

    function saySon() {
        # 尝试访问当前命名空间中的子命名空间 BinaryMoon 中的 saySelf() 函数
        return BinaryMoon\saySelf();
    }
}

namespace HOME\RedHeart\BinaryMoon {
    function saySelf() {
        return __NAMESPACE__;
    }
}

# 全局命名空间
namespace {
    # 尝试访问 HOME\RedHeart\BinaryMoon 命名空间下的 saySelf() 函数
    var_dump(\HOME\RedHeart\BinaryMoon\saySelf());
    # 尝试访问 HOME\RedHeart 命名空间下的 saySelf() 函数
    var_dump(HOME\RedHeart\saySelf());
    # 尝试访问 HOME\RedHeart 命名空间下的 saySon() 函数
    var_dump(\HOME\RedHeart\saySon());
}

执行效果

string(24) "HOME\RedHeart\BinaryMoon"
string(13) "HOME\RedHeart"
string(24) "HOME\RedHeart\BinaryMoon"

namespace 关键字

namespace 的两大功能

在 PHP 中,namespace 关键字常用于 命名空间的声明当前命名空间下元素的访问

使用 namespace\ 访问当前命名空间下的元素

在使用 namespace 访问当前命名空间元素时,namespace 后需要紧跟反斜线 \,后跟子命名空间或 其他元素(类、接口、函数 和 常量)。对此请参考如下示例:




namespace HOME\RedHeart {
    const CONSTANT = __NAMESPACE__;
    function func() {}
    class MyClass {}
}

namespace HOME\RedHeart\BinaryMoon {
    const CONSTANT = __NAMESPACE__;
    function func() {}
    class MyClass {}
}

namespace HOME\RedHeart {
    # 访问当前命名空间下除子命名空间外的其他元素
    var_dump(namespace\CONSTANT);
    new namespace\MyClass();
    namespace\func();
    # 访问当前命名空间的子命名空间 BinaryMoon 内的元素
    var_dump(namespace\BinaryMoon\CONSTANT);
    new namespace\BinaryMoon\MyClass();
    namespace\BinaryMoon\func();
}

执行结果

string(13) "HOME\RedHeart"
string(24) "HOME\RedHeart\BinaryMoon"

未雨绸缪

第一深情

在使用非限定名称对元素进行访问时,类名称 总是基于当前命名空间进行解析。因此 在其他命名空间中尝试访问全局命名空间中的类时,必须使用完全限定名称。对此,请参考如下示例:




namespace {
    # 在全局命名空间中定义类 MyClass
    class MyClass {}
}

namespace HOME {
    # 在 \HOME 全局命名空间中尝试
    # 使用非限定名称对 \MyClass 类进行访问
    $myClass = new MyClass();
}

执行效果

即使在 当前命名空间中(非全局命名空间) 未找到名为 MyClass 的类,PHP 也 不会尝试将其解析为全局命名空间中的元素

PHP Fatal error:  Uncaught Error: Class 'HOME\MyClass' not found in C:\test.php:12
Stack trace:
#0 {main}
  thrown in C:\test.php on line 12

向上突围

函数与常量的名称与类名称的解析存在差异。在使用非限定名称对元素进行访问时,如果当前命名空间中不存在该函数或常量,PHP 会 退而使用全局空间中的函数或常量。对此,请参考如下示例:




namespace {
    # 在全局命名空间中定义函数 sayHello 与 常量 CONSTANT
    function sayHello() {
        print('Hello World' . "\n");
    }

    const CONSTANT = __NAMESPACE__;
}

namespace HOME {
    # 在 \HOME 命名空间中,
    # 尝试使用非限定名称对元素进行访问。
    sayHello();
    var_dump(CONSTANT);
}

执行效果

Hello World
string(0) ""

(完全)限定名称下的未定义常量

PHP8 以下

在 PHP8 以下版本中,尝试访问未定义常量将导致 Warning 异常,该常量的名称的字符串形式将作为访问结果。对此,请参考如下示例:




# 尝试访问未定义常量
var_dump(CONSTANT);

执行效果

PHP7.2.5 中执行上述代码,得到如下结果:

PHP Warning:  Use of undefined constant CONSTANT - assumed 'CONSTANT' (this will throw an Error in a future version of PHP) in C:\test.php on line 5
string(8) "CONSTANT"

PHP8 及以上

在 PHP8 及以上版本中,尝试访问未定义常量将导致 Fatal 异常,PHP 将因此立即终止程序。对此,请参考如下示例:



# 尝试访问未定义常量
var_dump(CONSTANT);

执行效果

PHP8.0.0 中执行上述代码,得到如下结果:

PHP Fatal error:  Uncaught Error: Undefined constant "CONSTANT" in C:\test.php:5
Stack trace:
#0 {main}
  thrown in C:\test.php on line 5

任何情况下的(完全)限定名称下的未定义常量

在任何 PHP 版本中,使用完全限定名称或限定名称对未定义常量进行访问都将导致 Fatal 异常,PHP 程序都将为此立即终止。对此,请参考如下示例:




# 尝试访问未定义常量
namespace HOME\RedHeart {
}

namespace HOME {
    # 尝试通过完全限定名称对未定义常量进行访问
    var_dump(\HOME\RedHeart\CONSTANT);
}



# 尝试访问未定义常量
namespace HOME\RedHeart {
}

namespace HOME {
    # 尝试通过限定名称对未定义常量进行访问
    var_dump(RedHeart\CONSTANT);
}

执行效果

PHP7.2.5 中,执行上述两组示例都将得到如下类似结果:

PHP Fatal error:  Uncaught Error: Undefined constant 'HOME\RedHeart\CONSTANT' in C:\test.php:10
Stack trace:
#0 {main}
  thrown in C:\test.php on line 10

你可能感兴趣的:(后端,PHP,命名空间,namespace,关键字,命名空间及其成员的访问,访问未定义常量在各情况下的差异,三种名称)