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 (CCC)   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