分类
后端

php 命名空间

什么是命名空间

  • 命名空间(PHP 5 >= 5.3.0, PHP 7)
  • 从广义上来说,命名空间是一种封装事物的方法。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。
  • 在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题
    • 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突
    • 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
  • 名为PHP或php的命名空间,以及以这些名字开头的命名空间(例如PHP\Classes)被保留用作语言内核使用,而不应该在用户空间的代码中使用。

定义命名空间与子命名空间

  • 虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)接口函数常量
  • 命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字。
  • 所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前
  • 同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。
  • 与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:

在同一个文件中定义多个命名空间

  • 也可以在同一个文件中定义多个命名空间
  • 在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。
  • 全局的非命名空间中的代码命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称namespace 语句加上大括号括起来

使用命名空间

类名可以通过三种方式引用:

  • 非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();
  • 限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();
  • 完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod()。

namespace关键字和__NAMESPACE__常量

PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__ 魔术常量和namespace关键字。

  • 常量NAMESPACE的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串
  • 常量 NAMESPACE动态创建名称时很有用
  • 关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中的 self 操作符。

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

允许通过别名引用导入外部的完全限定名称,是命名空间的一个重要特征。

  • 所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。
  • 在PHP中,别名是通过**操作符 use **来实现的.
  • 为了简化操作,PHP还支持在一行中使用多个use语句 ,导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是:
  • 导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。

命名空间优先策略

在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。

  • 类名称总是解析到当前命名空间中的名称。因此在访问系统内部不包含在命名空间中的类名称时必须使用完全限定名称
  • 对于函数常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。

名称解析规则

命名空间名称定义 说明
非限定名称Unqualified name 名称中不包含命名空间分隔符的标识符,例如 Foo
限定名称Qualified name 名称中含有命名空间分隔符的标识符,例如 Foo\Bar
完全限定名称Fully qualified name 名称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如 \Foo\Bar。 namespace\Foo 也是一个完全限定名称。
名称解析遵循规则 举例
完全限定名称的函数,类和常量的调用在编译时解析 new \A\B 解析为类 A\B
所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换 如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。
在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称 在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e()
非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称) 如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。
命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的 1.在当前命名空间中查找名为 A\B\foo() 的函数 2.尝试查找并调用 全局(global) 空间中的函数 foo()。
命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的 new D\E()的解析:1.在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。 2.尝试自动装载类 A\B\D\E。

发表评论

电子邮件地址不会被公开。 必填项已用*标注