[PHP][PrestaShop]載入機制
PHP中當需要使用另一個檔案中的類或物件時,需要先require或include這個檔案。require和include的區別是require失敗後出告警,include失敗後出warning。
PrestaShop在載入這部分有一些自己獨到的處理,一起看下。
1. 訪問順序:
index.php -> config/config.inc.php -> config/autoload.php -> classes/PrestaShopAutoload.php
index.php是PrestaShop的總入口
config.inc.php做一些配置,其中還呼叫了defines.inc.php(包含了大部分路徑的定義),settings.inc.php(包含了資料庫定義)等等
autoload.php感覺這一步有點多餘,完全可以在config.inc.php裡直接require PrestaShopAutoload。也許是保留做未來功能擴充套件或者是為了支援多商店,who knows
PrestaShopAutoload.php生成所有用到的.php檔案的列表,並存儲在cache/class_index.php檔案中;定義了供spl_autoload_register使用的回撥函式,後面重點分析下這個class
2. PrestaShop使用了spl_autoload_register,我們先來簡單看下這個函式的意義
spl_autoload_register —
這是php.net上的原話,我理解就是通過它php提供了由使用者自己來處理autoload的可能,並且他相對與使用者實現__autoload()來說更進一步,相當於可以定義多個__autoload()函式。
在PrestaShop中是這樣使用這個函式的:
require_once(_PS_CLASS_DIR_.'PrestaShopAutoload.php');
spl_autoload_register(array(PrestaShopAutoload::getInstance(), 'load'));
(autoload.php)
這個可以理解為把PrestaShopAutoload類中的load方法作為autoload的處理函式
3. PrestaShopAutoload::getInstance(),看看初始化做了些啥
首先,getInstance()方法中是經典的單例模式的實際運用,確保一個類只有一個物件。順便一說,Presta大量使用了單例模式。
在__construct中做了兩件事情,判斷有沒有cache/class_index.php這個檔案,有就include這個檔案,沒有則初始化這個檔案,這個檔案是所有類的一個索引,供load方法使用,結構如下:
'Dispatcher' =>
array (
'path' => '',
'type' => 'class',
'override' => false,
),
'DispatcherCore' =>
array (
'path' => 'classes/Dispatcher.php',
'type' => 'class',
'override' => false,
),
初始化讀取了classes,controllers,override/classes,override/controllers下的所有的php檔案。
4. load方法探究
Presta的這個機制還是很有意思的,不但很好的解決了自動載入的問題,還順便帶來了核心類都可以被overload的好處。上面我們看到Dispatcher這個方法在索引中的儲存結構,那我們看下他是如何被引入和初始化的。
這是index.php的第二行:
Dispatcher::getInstance()->dispatch();
初看有點唬人,沒引入呢,就直接用了。但我們看過上面的描述就應該知道,在這個地方如果Dispatcher並沒有被引入過,那麼就會由load()這個方法來處理。
load()收到的$classname是Dispatcher,那麼他會首先判斷這個類名是不是以Core結尾的,如果是,那麼載入Core所指向的檔案。如果不是,先判斷索引裡面該類下有沒有path,如果有,則把這個自定義的類和core類一起載入。從這裡看,這個自定義類應該需要繼承core類。如果沒有則只加載core類,並自動新增一個繼承core類的名為Dispatcher的類,方便呼叫。
總結:至此,大概瞭解了Presta的載入機制,對我們在Presta中做二次開發有如下好處:
1. 看中哪個類了,只要在classes/controllers/override這些目錄下,直接類名::getInstance()使用即可
2. 看著那個類的功能不滿意,自己寫一個繼承它的類放在override中即可直接使用