PHP 的 autoload 与 namespace

autoload(5.1加入) 和 namespace(5.3加入),可见这俩并非 PHP 语言不可或缺,而是为了针对特定的问题所引入的一种解决方案。

0.先说 symbol table,这是根本。PHP 解释器在执行的时候,内部维护着的一个表,类似于:

|--------+----------+----------------|
| symbol | type     | memory address |
|--------+----------+----------------|
| Name1  | Class    |     0x00DFF1A8 |
| Name2  | Class    |     0x00DFF1B8 |
| Name1  | Function |     0x00DFF1C8 |
| Name1  | Variable |     0x00DFF1D8 |
| ...    | ...      |            ... |

类名、函数名、变量名这些都是 symbol
PHP 解释器在执行(载入)每一个 .php 文件时,遇到一个 类定义、函数定义、变量定义 就往 symbol table 添入一行(这也是为什么 PHP 解释器能够发现重复定义)。在接下来的执行中,PHP 解释器遇到 "实例化一个类" 的代码,就查一下 symbol tabletype Class 下有没有这个 类名,如果没有,则报错"类未定义"。

1.有了上面的铺垫,按照加入PHP的先后顺序,先说 autoload。上面 "实例化一个类" 的这个流程,其实是有改进余地的,在其查 symbol table 没有找到 类名 之后,可以插入一个步骤,这个步骤负责从文件系统找到 类定义所在的.php文件 并当即载入,这个步骤,就叫 autoload
autoload 内的匹配规则是需要你动手来写的,最常见的做法是 类名类定义所在.php文件名 两者取同名:

spl_autoload_register(function ($class_name) {
    include $class_name . '.php';
});

2.在 PHP 中加入 namespace 后,其 symbol table 类似于:

|-----------+--------+----------+----------------|
| namespace | symbol | type     | memory address |
|-----------+--------+----------+----------------|
| \         | Name1  | Class    |     0x00DFF1A8 |
| \         | Name2  | Class    |     0x00DFF1B8 |
| \         | Name1  | Function |     0x00DFF1C8 |
| \         | Name1  | Variable |     0x00DFF1D8 |
| ...       | ...    | ...      |            ... |

PHP 解释器在查 symbol table 时加入了对 namespace 的判断
假设你给自己所有的 .php 的首行放

namespace SF\yahu;

PHP 解释器在执行你的代码后,其 symbol table 类似于:

|-----------+--------+----------+----------------|
| namespace | symbol | type     | memory address |
|-----------+--------+----------+----------------|
| \         | Name1  | Class    |     0x00DFF1A8 |
| \         | Name2  | Class    |     0x00DFF1B8 |
| \         | Name1  | Function |     0x00DFF1C8 |
| \         | Name1  | Variable |     0x00DFF1D8 |
| ...       | ...    | ...      |            ... |
| SF\yahu   | Name1  | Class    |     0x00DFF2A8 |
| SF\yahu   | Name2  | Class    |     0x00DFF2B8 |
| SF\yahu   | Name1  | Function |     0x00DFF2C8 |
| SF\yahu   | Name1  | Variable |     0x00DFF2D8 |
| ...       | ...    | ...      |            ... |

别人在实例化 你的代码中的类 的时候,须这么写:

$obj = new SF\yahu\Name1();

看看上面起分隔作用的这个 \,眼不眼熟?有没有让你联想到 文件路径 中起分隔作用的 /?那么 autoload 中的匹配规则你有想法了吗?
想细究的话可以看 Composer 的实现。

3.use Some\NS; 不是必须的,你可以先试着不用 use Some\NS;,等你敲累了后再自行决定用不用 :)。

相关推荐