PHP 命名空间

命名空间抽样模型

编程的本质是抽象,命名空间是一种编程抽象模型,它表示了一个标识符的可见范围。生活中我们会经常遇到两个人完全重名的情况,但是他们是不会被混淆的,因为他们来自不同的家庭,如果两人都来自同一个家庭,那么哥哥叫“小明”,弟弟绝对就不会再起名为“小明”了,我们可以认为每一个家庭都是一个命名空间。这种抽象模型在计算机中也被广泛应用,如计算机操作系统中同一个目录下是不允许有两个相同文件名的文件的,但不同的目录下确可以有文件名相同的文件。如

1
2
$ whereis python
python: /usr/bin/python2.6 /usr/bin/python /usr/local/bin/python2.6

python2.6 分别在不同的目录下,假设要使用 /usr/bin/ 下的 python2.6 应按如下方式调用,

1
$ /usr/bin/python2.6 -h

要使用 /usr/local/bin 下的 python2.6 则应如下调用,

1
$ /usr/local/bin/python2.6

除了使用绝对路径(绝对命名空间)方式调用之外,也可以通过文件的相对路径调用,假设当前路径位于 /usr/ 下则,

1
$ ./bin/python2.6 -v

即可调用到 /usr/bin/python2.6

命名空间是一种编程抽象模型,除了在操作系统中的应用,编程语言中也有广泛应用命名空间。在 PHP 中,命名空间主要用来解决两类问题:

  • 命名冲突——用户编写的代码与PHP内部的或第三方的类、函数、常量、接口名字冲突
  • 提高可读性——为很长的标识符名称创建一个别名的名称,提高源代码的可读性

PHP命名空间提供了一种将相关的类、函数、常量和接口组合到一起的途径,不同命名空间的类、函数、常量、接口相互隔离不会冲突,注意:PHP命名空间只能隔离类、函数、常量和接口,不包括全局变量。

命名空间使用

命名空间申明

命名空间使用 namespace 申明,命名空间必须在除了 declare关键字以外的其他代码之前申明,也就是说只要没有 declare 关键字,命名空间的申明都必须放在文件的开头。假设有一个基类 app/controllers/Controller.php

1
2
3
4
5
6
7
<?php
namespace App\Controllers;

class Controller {

}
?>

需要特别注意的是:定义命名空间时省略了根空间符号 “\”,namespace App\Controllers; 定义的命名空间实际上是 \App\Controller,因此再引用命名空间时一定要记得加上根空间符号”\”,这种特殊方式实际上是可以类比的,如果你熟悉 shell 编程,你就会知道这和 shell 中的变量是一样的,shell 变量再申明或赋值的时候省略了 “$”,如

1
2
3
name = 'Syncher'; # 申明
...
echo $name; # 使用

命名空间引用

app/controllers/user/LoginController.php 中要继承 app/controllers 中的 Controller 类,

  • 首先需要引入文件
  • 然后引用命名空间
1
2
3
4
5
6
7
8
<?php
namespace App\Controllers\User;

include '../Controller.php';

class LoginController extends \App\Controllers\Controller {
// some codes here ...
}

引用命名空间的方式有如下三种,

  • 非限定名称

    非限定名称,或不包含前缀的类名称,会被解析为当前命名空间下。相当于文件系统中的当前路径,如下所示的 Controller 类将被解析为 \App\Controllers\User\Controller

    1
    2
    3
    4
    5
    6
    namespace App\Controllers\User;

    include '../Controller.php';
    class LoginController extends Controller {
    // some codes here ...
    }

    而当前命名空间下没有该类,因此会报如下错误,

  • 限定名称

    限定名称,或包含前缀的名称和非限定名称类似,相当于文件系统中的相对路径,如下代码中的 Controller 类将被解析为 \App\Controllers\User\App\Controllers\Controller

    1
    2
    3
    4
    5
    6
    namespace App\Controllers\User;

    include '../Controller.php';
    class LoginController extends App\Controllers\Controller {
    // some codes here ...
    }

    而当前命名空间下没有该类,因此会报如下错误,

  • 完全限定名称

    完全限定名称,或包含了全局前缀操作符的名称,相当于文件系统中的相对路径。如下为正确的对 Controller 类的继承,

    1
    2
    3
    class LoginController extends \App\Controllers\Controller {
    // some codes here ...
    }

除了在标识符前面添加限定词之外,还可以使用 use 导入使用类,如use \App\Controllers\Controller as Controller; as 是指定导入类的别名,如果导入类的别名和原名相同则可省略别名的描述。

1
2
3
4
5
6
7
namespace App\Controllers\User;
use \App\Controllers\Controller; // 相当于:use \App\Controllers\Controller as Controller;

include '../Controller.php';
class LoginController extends Controller {
// some codes here ...
}

根据 PSR 要求,命名空间应与文件路径一致,比如 Laravel 默认生成的 app/Http/Controllers/Auth/LoginController.php,其命名空间为 App\Http\Controllers\Auth

1
2
3
4
5
6
7
8
9
10
11
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
// code here ...
}

命名空间与文件路径一致是 PSR 的规范,但这并不意味这命名空间和文件名有关联,实际上二者并无关系,这样规范是为了更加方便自动加载。

本文标题:PHP 命名空间

文章作者:Pylon, Syncher

发布时间:2018年08月01日 - 10:08

最后更新:2023年03月11日 - 17:03

原始链接:https://0x400.com/fundamental/programming-language/php/php-namespace/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。