乐趣区

PHP-的-autoload-与-namespace

这是我回答问答板块一个问题的答案,也是我在 segmentfault 发的第一篇文章,求知路上,与诸位共勉。

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;,等你敲累了后再自行决定用不用 :)。

退出移动版