這篇是為了研究 Joomla! 1.6 的整個頁面讀取過程做的筆記。
從 index.php 開始可以看見整個loading過程非常有結構的分成初期 載入 framework 與接下來的四個執行階段:
- Initialise
初始化,載入整個 framework 並建立核心 Application 來進行接下來的流程。 - Route
處理網址。取得接收到的參數或將SEF網址轉成參數,存入全域的 Request 資料中。方便之後任何應用程式提取。 - Dispatch
分派該讀取的元件、模組等等,輸出至緩衝區。 - Render
取得該頁面使用的模版與參數,將所有該輸出的html輸出完成,存入緩衝區中。
最後的 echo $app 就等於執行 $app->__toString() 這個php的魔術函式。並判斷是否要先 gzip 後再輸出。
並且從 JProfiler 提供的debug資訊中,可以看見整個頁面的載入時間分配(以飛鳥實驗室為主):
Application 0.005 seconds (+0.005); 0.27 MB (+0.27) - afterLoad //載入framework.php 之後
Application 0.122 seconds (+0.117); 3.08 MB (+2.81) - afterInitialise
Application 0.147 seconds (+0.025); 3.76 MB (+0.68) - afterRoute
Application 0.313 seconds (+0.166); 6.53 MB (+2.77) - afterDispatch
Application 0.480 seconds (+0.167); 6.94 MB (+0.42) - afterRender
會發現載入 framework 的時間只佔了整體時間的幾乎 1% ,初始化只佔了約四分之一的時間。
若之後模版、套件等漸漸肥大之後,比例差距會更大。
因此簡單說來 Joomla! 吃效能不在於本身程式架構的問題,而是因為其較為華麗複雜的元件與佈景分派系統從各方面拖慢效能的。
Joomla 1.6 API 執行順序
- index.php
- defined.php 是否存在
- 載入defined.php
- define something
- 載入framework.php
- Joomla system checks
- 判斷 installation
- 載入import.php
- JLoader
-
JLoader::import('joomla.base.object');
-
JLoader::import('joomla.environment.request');
-
JLoader::import('joomla.environment.response');
-
JLoader::import('joomla.factory');
-
JLoader::import('joomla.version');
-
JLoader::import('joomla.error.error');
-
JLoader::import('joomla.error.exception');
-
JLoader::import('joomla.utilities.arrayhelper');
-
JLoader::import('joomla.filter.filterinput');
-
JLoader::import('joomla.filter.filteroutput');
-
JLoader::register('JText', dirname(__FILE__).DS.'methods.php');
-
JLoader::register('JRoute', dirname(__FILE__).DS.'methods.php');
- 載入 configuration.php
- new Config()
- 判斷 是否開啟錯誤回報 然後unset config
- 如果開啟錯誤回報 啟動 $_PROFILER
-
jimport('joomla.application.menu'); //Jmenu
-
jimport('joomla.user.user'); //JUser
-
jimport('joomla.environment.uri'); //JURI
-
jimport('joomla.html.html'); //JHtml
-
jimport('joomla.utilities.utility'); //JUtility
-
jimport('joomla.event.event'); //JEvent
-
jimport('joomla.event.dispatcher'); //JDespatcher
-
jimport('joomla.language.language'); //JLanguage
-
jimport('joomla.utilities.string'); //Jstring
- $app = JFactory::getApplication('site');
- JApplication::getInstance( 'site' , $config, $prefix); //or 'administrator'
- new JSite or JAdministrator and parent JApplication::construct()
- JConfig();
- $app->initialise();
- jimport('joomla.plugin.helper');
- 判斷使用者的 editor
- import system plugin
- Event: onAfterInitialise
- $app->route();
- get URI
- JRequest::set($result, 'get', false);
- Event: onAfterRoute
- $app->dispatch();
- getDocument();
- setTitle()
- setMeatDesc()
- renderCompontent() and setBuffer();
- Event: onAfterDispatch
- $app->render();
- get Template and params
- Event: onBeforeRender
- is Cache?
- JResponse::setBody($document->render($caching, $params));
- Event: onAfterRender
- echo $app; (same as $app->__toString(); )
在 Initialise 之前已載入的 API 檔案:
- [jobject] => D:\www\joomla16\libraries\joomla\base\object.php
- [jrequest] => D:\www\joomla16\libraries\joomla\environment\request.php
- [jresponse] => D:\www\joomla16\libraries\joomla\environment\response.php
- [jfactory] => D:\www\joomla16\libraries\joomla\factory.php
- [jversion] => D:\www\joomla16\libraries\joomla\version.php
- [jerror] => D:\www\joomla16\libraries\joomla\error\error.php
- [jexception] => D:\www\joomla16\libraries\joomla\error\exception.php
- [jarrayhelper] => D:\www\joomla16\libraries\joomla\utilities\arrayhelper.php
- [jfilterinput] => D:\www\joomla16\libraries\joomla\filter\filterinput.php
- [jfilteroutput] => D:\www\joomla16\libraries\joomla\filter\filteroutput.php
- [jtext] => D:\www\joomla16\libraries\joomla\methods.php
- [jroute] => D:\www\joomla16\libraries\joomla\methods.php
- [jprofiler] => D:\www\joomla16\libraries\joomla\error\profiler.php
- [jmenu] => D:\www\joomla16\libraries\joomla\application\menu.php
- [juser] => D:\www\joomla16\libraries\joomla\user\user.php
- [juri] => D:\www\joomla16\libraries\joomla\environment\uri.php
- [jhtml] => D:\www\joomla16\libraries\joomla\html\html.php
- [jutility] => D:\www\joomla16\libraries\joomla\utilities\utility.php
- [jevent] => D:\www\joomla16\libraries\joomla\event\event.php
- [jdispatcher] => D:\www\joomla16\libraries\joomla\event\dispatcher.php
- [jlanguage] => D:\www\joomla16\libraries\joomla\language\language.php
- [jstring] => D:\www\joomla16\libraries\joomla\utilities\string.php
因此以上物件或class都是在 onAfterInitialise 的事件中,Plugin 已經可以調用的 API。
由於 1.6 開始,Joomla! 採用 php5 的特點,大量使用 class 中的 static 與 private varible 來儲存 JFactory 與 JLoader 所呼叫過的物件資料。因此必須直接在class原始檔中 hack 加上 get_class_vars() 才能取得這些資料。日後再說明吧~