Re: [请益] 关于autoload

楼主: GALINE (天真可爱CQD)   2018-01-27 22:18:08
> → 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 的时候的内容变化
作者: tkdmaf (皮皮快跑)   2018-01-27 22:55:00
我有问题!为什么php是小姐?
作者: comicat (可米猫)   2018-01-28 01:29:00
推 详细
作者: wuwt4y (Poky)   2018-01-28 01:42:00
非常详细,感谢。
作者: ksks5222 (Prue)   2018-01-28 01:42:00
php觉得是妹妹比较好
作者: Kenqr (function(){})()   2018-01-28 03:57:00
作者: fezexp9987   2018-01-28 09:19:00
推推
作者: tkdmaf (皮皮快跑)   2018-01-28 11:31:00
可是人家php明明是一只大象………(疑?)
楼主: GALINE (天真可爱CQD)   2018-01-28 11:55:00
https://i.imgur.com/OcqjqZR.jpg 是耳朵很大的朋友呢
作者: MOONRAKER (㊣牛鹤鳗毛人)   2018-01-28 17:44:00
大象就对
作者: tkdmaf (皮皮快跑)   2018-01-28 19:07:00
这样也行………I 服了 you
作者: onininon (万)   2018-01-28 22:03:00
实用推
作者: shvanta (vant)   2018-01-29 09:54:00
好文推
作者: newton2009 (好瘦唷QQ)   2018-01-29 18:50:00
好想按赞呀
作者: duke00184   2018-01-29 22:39:00
解说超详细的
作者: MangoTW (不在线上)   2018-01-30 02:24:00
精辟推
作者: bakedgrass (蒙古烤小草)   2018-01-30 02:41:00
推文的动物朋友让我喷笑
作者: ddtsatan   2018-01-30 08:34:00
作者: mcmj5566 (美江五六)   2018-01-30 09:24:00
作者: TFnight (二十四夜)   2018-01-31 14:43:00
推~
作者: locklose (允)   2018-02-02 18:09:00
好文推
作者: nfsong (圖書館我來了)   2018-02-11 01:06:00
作者: lolikung (干么查我?)   2018-02-16 20:00:00
感谢大大无私分享

Links booklink

Contact Us: admin [ a t ] ucptt.com