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\jinz;
PHP 解释器在执行你的代码后,其 symbol table 类似于:
|-----------+--------+----------+----------------|
| namespace | symbol | type | memory address |
|-----------+--------+----------+----------------|
| \ | Name1 | Class | 0x00DFF1A8 |
| \ | Name2 | Class | 0x00DFF1B8 |
| \ | Name1 | Function | 0x00DFF1C8 |
| \ | Name1 | Variable | 0x00DFF1D8 |
| ... | ... | ... | ... |
| SF\jinz | Name1 | Class | 0x00DFF2A8 |
| SF\jinz | Name2 | Class | 0x00DFF2B8 |
| SF\jinz | Name1 | Function | 0x00DFF2C8 |
| SF\jinz | Name1 | Variable | 0x00DFF2D8 |
| ... | ... | ... | ... |
别人在实例化 你的代码中的类 的时候,须这么写:
$obj = new SF\jinz\Name1();
看看上面起分隔作用的这个 \,眼不眼熟?有没有让你联想到 文件路径 中起分隔作用的 /?那么 autoload 中的匹配规则你有想法了吗?
想细究的话可以看 Composer 的实现,ThinkPHP5 的话你可以看 ProjectPath/thinkphp/library/Loader.php。
3.use Some\NS; 不是必须的,你可以先试着不用 use Some\NS;,等你敲累了后再自行决定用不用 :)。