Php 简明教程

PHP - Namespaces

我们经常将文件组织在不同的文件夹中。通常情况下,一个文件夹包含与某个目标、应用程序或类别相关联的文件。一个文件夹不能包含两个具有相同名称的文件,尽管不同的文件夹可能具有一个名称相同的文件,因此每个文件路径都是不同的。

PHP 中的命名空间理念有点类似。在 PHP 中,命名空间允许在不同上下文中使用相同名称的类或函数或常量,而不会出现任何冲突,从而封装这些项。

PHP 命名空间是根据它们的关联性对类/函数等进行的逻辑分组。正如同名的文件可以存在于两个不同的文件夹中一样,命名空间中也可以定义一个特定名称的类。此外,由于我们指定文件的完整路径来获取访问权限,因此我们需要指定类及其命名空间的完整名称。

随着应用程序规模的不断增大,包括许多类和函数定义,为每个类/函数提供一个唯一的名称可能会变得繁琐并且不够优雅。使用命名空间可让您以一种简洁的方式组织此类代码块。例如,如果我们需要声明一个 calculate() 函数来计算面积和税费,我们可以创建两个命名空间 area 和 tax,并在其中使用 calculate() 而不必将它们定义为类似 calculate_area() 和 calculate_tax() 的内容。

Advantages of Namespace

下面列出了一些使用 PHP 中的命名空间的优点 −

  1. 命名空间有助于避免某人使用第三方类/函数/常量定义的类/函数/常量之间的名称冲突。

  2. 命名空间提供了对 Extra_Long_Names 进行别名(或缩短)的能力,从而提高了源代码的可读性。

  3. PHP 命名空间提供了一种对相关的类、接口、函数和常量进行分组的方法。命名空间名称不区分大小写。

Defining a Namespace

PHP 的名称空间关键字用于定义新的命名空间。

namespace myspace;

包含命名空间的 “.php” 文件必须在文件顶部声明命名空间,然后再声明任何其他内容(声明指令除外)。在命名空间中声明类、函数和常量会影响其访问权限。

一个 PHP 脚本可以除了定义命名空间之外,还包含其他代码。为了加载在相同代码中定义的命名空间,PHP 具有“use”关键字。

use myspace;

Example

在以下 “hello.php” 脚本中,我们在 myspace 命名空间中定义了一个 hello() 函数,并在当前脚本中加载该命名空间之后对其进行调用。

<?php
   namespace myspace;
   function hello() {
      echo "Hello World";
   }
   use myspace;
   myspace\hello();
?>

它将生成以下 output

Hello World

请注意,您必须用名称空间完整的名称限定 hello() 函数,其中包括名称空间 - myspace\hello()。

Include Namespace

可以有一个脚本包含名称空间声明,以及在其中使用 include 语句加载该名称空间的另一个脚本。

a.php

<?php
   namespace myspace {
      function hello() {
         echo "Hello World in myspace";
      }
   }
?>

b.php

<?php
   include 'a.php';
   myspace\hello();
?>

它将生成以下 output

Hello World in myspace

在当前的脚本(如上所述的“b.php”)中,可能还有一个函数与 include 文件中函数名称相同。附加名称空间的完全限定函数,帮助解析器解决名称冲突。

Example

请看以下示例:

<?php
   include 'a.php';
   function hello() {
      echo "Hello World from current namespace";
   }
   hello();
   myspace\hello();
?>

它将生成以下 output

Hello World from current namespace
Hello World in myspace

Example

如上所述,名称空间声明必须在最上面,紧跟在 <?php 标签的后面。否则,解析器会抛出致命错误。

<?php
   echo "hello"
   namespace myspace;
   function hello() {
      echo "Hello World";
   }
   use myspace;
   myspace\hello();
?>

它将生成以下 output

PHP Parse error:  syntax error, unexpected token "namespace",
expecting "," or ";" in /home/cg/root/67771/main.php on line 4

上面的错误信息明确指出,在名称空间声明之前,只允许出现“declare 语句”。

<?php
   declare (strict_types=1);
   namespace myspace;
   function hello() {
      echo "Hello World";
   }
   use myspace;
   myspace\hello();
?>

Relative Namespace

可以通过相对于名称空间的路径引用当前名称空间中的对象,如函数、类和常量。

在下面的示例中,“b.php”包含一个带有 hello() 函数和 TEMP 常量的名称空间 space1\myspace。这些对象也在“a.php”中定义的名称空间 space1 中被定义。

显然,当“b.php”被包含在“a.php”时,“myspace”是“space1”的子空间。因此,通过对其相对名称空间(也是 TEMP 常量)加上前缀来调用来自“myspace”的 hello()。

b.php

<?php
   namespace space1\myspace;
   const TEMP = 10;
   function hello() {
      echo "Hello from current namespace:" . __NAMESPACE__ . ;
   }
?>

a.php

<?php
   namespace space1;
   include 'b.php';
   function hello() {
      echo "Hello from current namespace:" . __NAMESPACE__ . ;
   }
   const TEMP = 100;
   hello();            // current namespace
   myspace\hello();   // sub namespace

   echo "TEMP : " . TEMP . " in " . __NAMESPACE__ . ;
   echo "TEMP : " . myspace\TEMP  . " \\in space1\\myspace\n";
?>

它将生成以下 output

Hello from current namespace:space1
Hello from current namespace:space1\myspace
TEMP : 100 in space1
TEMP : 10 in space1\myspace

Absolute Namespace

也可以通过附加绝对名称空间路径来访问任何名称空间中的函数/常量。例如,“b.php”中的 hello() 是“\space\myspace\hello()”。

a.php

<?php
   namespace space1;
   include 'b.php';
   function hello() {
      echo "Hello from current namespace:" . __NAMESPACE__ . ;
   }
   const TEMP = 100;
   \space1\hello();	             //current namespace
   \space1\myspace\hello();	    //sub namespace

   echo "TEMP: " . \space1\TEMP . " in " . __NAMESPACE__ . ;
   echo "TEMP: " . \space1\myspace\TEMP  . " in space1\\myspace\n";
?>

NAMESPACE 是 PHP 中的预定义常量,用于返回当前名称空间的名称。

Namespace Rules

通过遵循以下规则,可以解决不同名称空间之间出现的函数/类/常量名称冲突:

  1. 不带名称空间分隔符符号(/)的名称空间标识符表示其正在引用当前名称空间。这是一个不合格的名称。

  2. 如果它包含分隔符符号,如 myspace\space1,则解析为 myspace 下的子名称空间 space1。这种类型命名是相对名称空间。

  3. 完全限定名称空间的名称以“\”字符开头。例如,“\myspace”或“\myspace\space1”。

  4. 完全限定名称解析为绝对名称空间。例如,\myspace\space1 解析为 myspace\space1 名称空间。

  5. 如果名称出现在全局名称空间中,“namespace\”前缀会被移除。例如,“namespace\space1”解析为 space1。

  6. 然而,如果它出现在另一个名称空间内,则其处理方式有所不同。例如,如果 namespace\space1 在 myspace 中,则它等同于“myspace\space1”。

  7. 限定名称中的名称的第一段根据当前类/名称空间导入表进行翻译。

  8. 如果没有导入规则适用,则在名称前加上当前名称空间。

  9. 类名类型名称根据类/名称空间导入表进行翻译,函数名称根据函数导入表进行翻译,常量根据常量导入表进行翻译。

  10. 对于不合格名称,如果未应用导入规则并且名称指向函数或常量,且代码在全局命名空间之外,则该名称在运行时解析。首先,它从当前名称空间查找函数,然后尝试查找并调用全局函数。