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