0%

Namespaces in PHP

(具体定义和意义不再复述)

版本

PHP 7.2.34

用法

  1. namespace用于声明一个命名空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?php
    # 声明一个命名空间:app
    namespace app;
    # print: app
    echo __NAMESPACE__;

    # 声明一个命名空间:app\controllers
    namespace app\controllers;
    # print: app\controllers
    echo __NAMESPACE__;
    ?>
    • namespace后路径被解析为”全局空间路径”,不能带前缀’\‘,有则报错
    • 不能以’\‘结尾,有则报错
    • The Namespace name PHP, and compound names starting with this name (like PHP\Classes) are reserved for internal language use and should not be used in the userspace code.

    • 如上例一个文件可以声明多个命名空间,但通常不建议这么做
    • 同一个命名空间可在多个文件中声明
  2. use ...(as ...); 用于引入其他命名空间到当前命名空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?php

    namespace banana;
    const COLOR = 'yellow';

    # 命名空间,大小写不敏感
    namespace APPLE;
    const COLOR = 'red';

    namespace aa;

    # 用:use \banana; 也可以
    use banana;

    # print: yellow
    echo banana\COLOR;

    use apple as a;
    # print: red
    echo a\COLOR;
    ?>
    • 命名空间关键字大小写不敏感
    • use后路径被解析为”全局空间路径”,带不带前缀’\‘都可以,均不报错
    • 不能以’\‘结尾,有则报错
  1. 对命名空间中对象的访问
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     <?php

    namespace fruit\banana;

    const COLOR = 'yellow';
    class ClassName {
    public function __construct()
    {
    echo __METHOD__;
    }
    }

    namespace fruit;

    # print: yellow
    echo banana\COLOR;
    # print: fruit\banana\ClassName::__construct
    $n = new banana\ClassName();
    ?>

注意事项

“全局空间”的空间声明及其内的对象是否带前缀’\‘

声明命名空间和访问对象时表现有所不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

# 声明时不需要前缀'\',有则报错:Uncaught Error: Undefined constant 'app'
# namespace \app;
namespace app;
const COLOR = 'red';

# print: app
echo __NAMESPACE__;


namespace webapp;

# 报错:Uncaught Error: Undefined constant 'webapp\app\COLOR'
# echo app\COLOR;

# print: red
echo \app\COLOR;
?>

  • namespace声明命名空间不需要前缀’\‘,因为namespace后必须跟”全局空间路径”,那么前缀的’\‘也就没必要了(既然全为”全局空间路径”,则可以统一省略前缀’\‘,解析时再按照”全局解析”就可以了)
    • namespace 后路径若带前缀’\‘,则会报错
    • use后也必须跟”全局空间路径”,也按照”全局空间路径”来解析,但加不加前缀’\‘都可以
  • 在访问对象时,若是相对于”全局空间路径”的对象,必须带’\‘,否则就是相对于当前命名空间的对象,例如上文的:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    namespace webapp;

    # 访问: webapp\app\COLOR
    echo app\COLOR;

    # 访问:app\COLOR
    echo \app\COLOR;
    ?>

声明命名空间时不需要前缀’\‘,而在实际对象访问时却要加上前缀’\‘。namespace处加上前缀会报错,use加上前缀却不报错。
此处不知道为什么要这么设计,个人感觉很没必要,太容易误导了。

关键字namespace的特殊用途

当对象namespace前缀时,代表当前命名空间原始对象,而不包括后导入对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace fruit\banana;

class Banana {
public function __construct() {
echo __METHOD__;
}
}

namespace fruit\apple;

class Apple {
public function __construct() {
echo __METHOD__;
}
}

use fruit\banana\Banana;

# print: fruit\banana\Banana::__construct
$b = new Banana();
# 报错:Uncaught Error: Class 'fruit\apple\Banana' not found
# $b = new namespace\Banana();
# print: fruit\apple\Apple::__construct
$b = new Apple();
# print: fruit\apple\Apple::__construct
$b = new namespace\Apple();
?>

Banana为后导入对象,new Banana()可以成功,但new namespace\Banana()则会失败

define可跨命名空间声明常量

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

namespace app;
define('app\sub\YEAR', 2021);


namespace app\sub;
# print: 2021
echo YEAR;
?>

当前空间不存在时,不同对象表现方式不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace {
const NAME = 'Tom';
class ClassName {
public function __construct() {
echo __METHOD__;
}
}
}

namespace app {
# print: Tom
echo NAME;
# 报错:Uncaught Error: Class 'app\ClassName' not found
$c = new ClassName();
}
?>
  • 常量/函数:当前命名空间若没有,尝试向上级空间找,,若找到则调用;找到”全局空间”还没有,则报错
  • 类:当前命名空间若没有直接报错

Reference & Thanks