这是我回答问答板块一个问题的答案,也是我在 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 table
里 type
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;
,等你敲累了后再自行决定用不用 :)。