PHP 命名空间详解

文章目录

  • 一、概述
  • 二、定义命名空间
    • A. 单个命名空间
    • B. 多个命名空间
  • 三、使用命名空间
    • A. 一般
    • B. 别名/导入
    • C. 解析优先级
  • 四、PHP动态语言特性和命名空间

一、概述

PHP的官方文档关于这命名空间讲得乱七八糟的,于是重新整理了一下。

从广义上来说,命名空间是一种封装事物的方法,PHP 命名空间提供了一种将相关的类、函数和常量组合到一起,并与其他的同类隔离的途径。
在PHP中,命名空间用来解决用户在创建可重用的代码如类或函数或常量时,发生的用户代码与PHP内部的类/函数/常量或与第三方的类/函数/常量之间的命名冲突(重复)的问题。其次,也提供了为很长的标识符名称(通常是为了缓解命名冲突问题)创建一个别名的功能,以提高源代码的可读性。

二、定义命名空间

A. 单个命名空间

命名空间通过关键字 namespace 来声明,以分号;结束。如果在一个文件中包含命名空间,那么在"


    namespace MyName;
?>

PHP 命名空间也允许指定层次化的命名空间的名称。


    namespace MyName\SubName;
?>

全局空间


    namespace {
        //code goes here
    }
?>

虽然任意合法的PHP代码都可以包含在命名空间(同一个文件)中,但只有下列元素会受命名空间的影响:

  • 类(包括抽象类和traits)
  • 接口
  • 函数
  • 常量

其他代码语句如变量赋值、函数调用等,不管书写于哪个命名空间内,都作用于全局命名空间。

B. 多个命名空间

在同一个文件中定义多个命名空间,有两种方法可以做到,但在实际编程中,非常不提倡在同一个文件中定义多个命名空间。

  1. 第一种 顺序

    namespace MyName1;
    /* scope of MyName1 */

    namespace MyName2;
    /* scope of MyName2 */
?>
  1. 第二种 大括号(在大括号之外不应有任何代码)

    namespace MyName1{
    /* scope of MyName1 */
    }

    namespace MyName2{
    /* scope of MyName2 */
    }

    namespace {
    /* scope of global namespace
            全局命名空间        */
    }

    namespace / {
    /*  Syntax ERROR   */
    }
?>

由此也可以引出命名空间作用域(scope)的概念,某个命名空间只在它的作用域以内有效。
命名空间最大的作用域只及于一个文件之内。

三、使用命名空间

A. 一般

在PHP中,可通过三种方式引用命名空间:

  • 非限定名称
  • 限定名称
  • 绝对限定名称

如果以文件路径作类比的话,以上三者可分别对应:相对文件名,相对路径名,绝对路径名。
另外,关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素,它等价于类中的 self 操作符。


    // file:/var/html/NS1.php
    namespace MyName1\subName{
        const NUM=10;    
    }

    namespace {                 //全局空间
        const NUM=0;
    }
?>


    // file:/var/html/NS2.php
    namespace MyName1;
    include("NS1.php");         //后续语句依然位于MyName1作用域内,不是MyName1\subName
    const NUM=20;

    echo NUM;                   //输出20,非限定名称引用,解析为\MyName1\NUM
    echo subName\NUM;           //输出10,限定名称引用,解析为\MyName1\SubName\NUM
    echo \MyName1\SubName\NUM   //输出10,绝对限定名称引用,解析为\MyName1\SubName\NUM
    echo \NUM;                  //输出0,绝对限定名称引用,解析为\NUM
    echo namespace\NUM;         //输出20,namespace关键字引用,解析为\MyName1\NUM
?>

B. 别名/导入

允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中创建的对其它的文件的符号连接。

  1. 必须使用完全限定名称。
  2. 前导的反斜杠是不必要的也不推荐的,因为导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析。
  3. 另外,use语句必须放在最外层。

    namespace NS2;
    include('NS1.php');             //不会继承NS1.php中的use语句
    const NUM=20;
    //导入命名空间
    use MyName\SubName as SubName;  
    use MyName\SubName;             //和上一句作用一样
    //导入一个全局类
    use ArrayObject;
    //导入一个函数(需要PHP 5.6+)
    use function MyName\SubName\functionName;
    use function MyName\SubName\functionName as fun;
    //导入一个常量(需要PHP 5.6+)
    use const MyName\SubName\CONSTANT;

    echo NUM;                       //输出20,解析为\NS2\NUM
    $obj=new SubName\myClass;       //解析为\MyName\SubName\myClass
    SubName\functionName();         //解析为\MyName\SubName\functionName()
    $var=new ArrayObject;           //解析为\ArrayObject
    fun();                          //解析为\MyName\SubName\functionName()
?>

C. 解析优先级

  1. 对于命名空间中的类,如果使用非限定名称,那么解析后的类不存在时,会抛出异常错误。
  2. 对于命名空间中的函数和常量,如果使用非限定名称,那么解析后的结果不存在时,会尝试使用全局空间中的同名元素,最后才抛出异常错误。

四、PHP动态语言特性和命名空间

  1. 必须使用完全限定名称,因为字符串中不会做相对解析。
  2. 前导的反斜杠是非必要的。

    // file:/var/html/NS1.php
    function fun1(){            //全局空间
        echo __FUNCTION__;
    }    
?>


    // file:/var/html/NS2.php
    namespace MyName;
    include("NS1.php");
    function fun1(){
        echo __FUNCTION__;
    }    

    $f='fun1';
    $f();                       //输出 fun1
    $f='\MyName\fun1';
    $f();                       //输出 MyName\fun1
    $f='MyName\fun1';
    $f();                       //输出 MyName\fun1  
?>

参考 https://www.php.net/manual/zh/language.namespaces.php

你可能感兴趣的:(PHP 命名空间详解)