作者GALINE (天真可爱CQD)
看板PHP
标题Re: [请益] 关於autoload
时间Sat Jan 27 22:18:08 2018
> → wuwt4y: 这样说是没错,只是想说php自己一定会先扫过,他才知道有
> → wuwt4y: 哪些东西
觉得有需要把这几点讲清楚
- PHP 怎麽处理 autoload
- PSR-0 / PSR-4 做了什麽
- composer 在干嘛
== PHP 本身怎麽处理 autoload ==
基本上,PHP 这个大小姐什麽都没做,都是叫别人做。
PHP 没有自己实作 autoload 这件事
但是 PHP 允许(或说要求)开发者自己定义怎麽自动载入没看过的 PHP class
`
spl_autoload_register()` 的第一个参数是个 function
(精确的说,callable)
当 PHP 看到没看过的 Class 的时候,就先会去呼叫那个 function,然後再检查是不是
Class 已经顺利载入了,如果没看过的 class 还是没看过,PHP 再喷出 fatal error
(以前会用 __autoload(),不过那是过去的事了,忘了他吧)
例如这段程式
```
spl_autoload_register(function($name){
echo "我没有真的载入 `{$name}` 呢啾咪 ^.<\n";
});
$a1 = new A;
```
实际执行会看到
```
我没有真的载入 `A` 呢啾咪 ^.<
PHP Fatal error: Uncaught Error: Class 'A' not found in /tmp/b.php:5
```
背後发生的事情大概是这样
- 首先透过 spl_autoload_register() 注册了一个 autoload function
- PHP 看到了自己不认识的 Class A,呼叫事先注册的 autoload function
- 这个 function 印出了一行嘲讽文字
- 然後什麽都没做,Class A 依然没被载入
- PHP 再检查一次是不是 Class A 已经载入,可以 new 他了
- PHP 发现 Class A 还是不存在,於是开骂:「找不到这个 Class 啦,你出老千」
另一个例子
```
spl_autoload_register(function($name){
echo "PHP 说他找不到 class {$name}\n";
eval("Class {$name} extends stdClass{}");
eval("Class {$name}{$name} extends stdClass{}");
});
$a1 = new A;
$a2 = new AA;
$a3 = new A;
```
只会印出一行
```
PHP 说他找不到 class A
```
背後的运作大概是这样
- 注册了 autoload function
- 看到了不认识的 class A,呼叫 autoload function
- 先印出「找不到 class A」字样
- 透过 eval 执行 `Class A extends stdClass{}` ,於是 class A 被定义了
- 透过 eval 执行 `Class AA extends stdClass{}` ,於是 class AA 被定义了
- PHP 现在认识 A 了,於是乖乖 new 了一个 A
- PHP 已经认识 AA (载入A的时候一并把 AA 载入了),所以直接 new 了一个 AA
- PHP 已经认识 A 了,所以又 new 了一个 A
要注意到 autoloading 机制本身跟 include 没有直接关系。
但实用上通常会把他们连在一起当成 combo 技来用。
例如,你可以注册一个这样子的 autoload function
```
spl_autoload_register(function($className){
include __DIR__ . "/lib/{$className}.php";
});
```
这样当你第一次用到某个 class 的时候
PHP 就会自动去 include lib 资料夹里面的同名档案
PHP 不会自动自发的去扫 lib 或 vendor 资料夹里面有什麽东西
他只是照着 autoloader 说的去做而已
可能有人会想「我没写过 autoload function 或 spl_autoload_register 耶?」
贴心小提示:你觉得 composer 做了什麽(笑
== PSR-0 / PSR-4 做了什麽 ==
PSR-0 / PSR-4 (或者说,所有的 PSR) 其实只是一种道德劝说。
PHP 没有自己支援这些功能,但是 PHP-FIG(可以想成 PHP 国是会议)呼吁大家
写 code 的时候要这麽写。
「如果你要写 autoloader 的话,你要把这些 class 的档案依照我讲的这样放喔」
大概是这种感觉。
虽然听起来有种出一张嘴的感觉,但 PSR 的建议大多很有价值,所以
很多人愿意照着他们的建议来做。
於是 PSR 就从道德劝说变成行规了。
概念上 PSR-0 跟 PSR-4 的 class loader 其实满单纯的,大概可以写成这样
```
spl_autoload_register(function($className){
$path = findPsr4Path($className); // 依照 class name 判断档案应该在哪里
include $path; // include 那个档案
});
```
不过那个 `
findPsr4Path()` 自己写起来有稍微麻烦一点...
== composer 在干嘛 ==
没人会想一直重写 PSR-0 / PSR-4 相容的 autoloader。
这种事当练习很有价值。但作为工作还满麻烦。
所幸 composer 除了「套件管理」以外还有个很重要的功能:
帮你写好符合 PSR-0 / PSR-4 规范的 autoloader
当执行 composer install 的时候,composer 会产生对应的 autoloader
而在执行
```
include __DIR__ . '/vendor/autoload.php';
```
的时候,其实就是在载入 composer 产生出来的 autoloader。
当你安装了一堆套件,里面可能有成百上千个 class,全部载入是十分浪费资源的行为
所以 composer 的 autoloader 只有在某个 class 真的用到的时候,才会去 include
对应的 PHP 档案。
另外是 composer 的 autoloader 不会在载入 class 的时候去扫整个资料夹。
因为 PSR-0 / PSR-4 已经严格定义好 class 名称跟档案名称的对应关系,所以只要
检查对应的那一个档案是否存在就可以了。
不过如果如果你是跑 `
composer install -o`, composer 会先扫过 vender 资料夹
里面所有的程式码,然後纪录在 class map (本身是个 array)里面,所以 install
的时间会变长,带来的好处是 autoloader 实际载入 class 的时候,只要检查
class map 里面的档案名称就可以了,每个载入的 class 都能少戳一次硬碟。
有兴趣的人可以观察一下
- vendor/composer/autoload_classmap.php
这个档案在带 -o 跟没有带 -o 的时候的内容变化
--
顶天立地:爱孩子就要支持萝莉控
http://goo.gl/Bha7e
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.27.93.85
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/PHP/M.1517062696.A.F70.html
※ 编辑: GALINE (114.27.93.85), 01/27/2018 22:19:49
1F:推 tkdmaf: 我有问题!为什麽php是小姐? 01/27 22:55
小姐比较可爱,如果是个少爷我会想把他头扭下来...
※ 编辑: GALINE (114.27.93.85), 01/27/2018 23:24:44
2F:推 comicat: 推 详细 01/28 01:29
3F:推 wuwt4y: 非常详细,感谢。 01/28 01:42
4F:推 ksks5222: php觉得是妹妹比较好 01/28 01:42
5F:推 Kenqr: 推 01/28 03:57
6F:推 fezexp9987: 推推 01/28 09:19
7F:推 tkdmaf: 可是人家php明明是一只大象………(疑?) 01/28 11:31
9F:→ MOONRAKER: 大象就对 01/28 17:44
10F:推 tkdmaf: 这样也行………I 服了 you 01/28 19:07
11F:推 onininon: 实用推 01/28 22:03
12F:推 shvanta: 好文推 01/29 09:54
13F:推 newton2009: 好想按赞呀 01/29 18:50
14F:推 duke00184: 解说超详细的 01/29 22:39
15F:推 MangoTW: 精辟推 01/30 02:24
16F:推 bakedgrass: 推文的动物朋友让我喷笑 01/30 02:41
17F:推 ddtsatan: 推 01/30 08:34
18F:推 mcmj5566: 推 01/30 09:24
19F:推 TFnight: 推~ 01/31 14:43
20F:推 locklose: 好文推 02/02 18:09
21F:推 nfsong: 推 02/11 01:06
22F:推 lolikung: 感谢大大无私分享 02/16 20:00