typecho流程原理和插件機制淺析(第二彈)
兜兜393 2014年04月02日 釋出
- 推薦 1 推薦
- 收藏 14 收藏,3.7k 浏覽
上一次說了 Typecho 大緻的流程,今天簡單說一下插件機制和插件的編寫方法。
還是先上index.php
if (!@include_once 'config.inc.php') {
file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
exit;
}
/** 初始化元件 */
Typecho_Widget::widget('Widget_Init');
/** 注冊一個初始化插件 */
Typecho_Plugin::factory('index.php')->begin();
/** 開始路由分發 */
Typecho_Router::dispatch();
/** 注冊一個結束插件 */
Typecho_Plugin::factory('index.php')->end();
細心的朋友可能會發現上一次
/** 注冊一個初始化插件 */
Typecho_Plugin::factory('index.php')->begin();
/** 注冊一個結束插件 */
Typecho_Plugin::factory('index.php')->end();
這兩行代碼我們并沒有提起,這是為什麼呢?這是因為上一期主要是分析系統執行流程,我們假設沒有安裝任何插件,而在沒有安裝插件的情況下這兩行代碼是沒有任何作用的。
衆所周知,目前大部分插件都采用鈎子機制,Typecho也不例外,這兩行代碼就是系統在index.php裡預先設定的兩個插件接口,分别是整個程式流程中第一個和最後一個接口。那這種插件接口是怎麼執行的呢?
我們以
HelloWorld
插件為例,
HelloWorld
插件所使用的接口在
admin/menu.php
,代碼如下:
<?php Typecho_Plugin::factory('admin/menu.php')->navBar(); ?>
HelloWorld
插件的代碼,在
usr/plugins/HelloWorld/Plugins.php
:
<?php
/**
* Hello World
*
* @package HelloWorld
* @author qining
* @version 1.0.0
* @link http://typecho.org
*/
class HelloWorld_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件方法,如果激活失敗,直接抛出異常
*
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function activate()
{
Typecho_Plugin::factory('admin/menu.php')->navBar = array('HelloWorld_Plugin', 'render');
}
/**
* 禁用插件方法,如果禁用失敗,直接抛出異常
*
* @static
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function deactivate(){}
/**
* 擷取插件配置面闆
*
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面闆
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
/** 分類名稱 */
$name = new Typecho_Widget_Helper_Form_Element_Text('word', NULL, 'Hello World', _t('說點什麼'));
$form->addInput($name);
}
/**
* 個人使用者的配置面闆
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
/**
* 插件實作方法
*
* @access public
* @return void
*/
public static function render()
{
echo '<span class="message success">' . Typecho_Widget::widget('Widget_Options')->plugin('HelloWorld')->word . '</span>';
}
}
Typecho 在資料庫 Options 表裡,有一個名為
plugins
字段,裡邊記錄了整個程式已激活插件的接口挂載情況,沒有激活任何插件時
plugins
字段是這樣的:
Array
(
[activated] => Array
(
)
[handles] => Array
(
)
)
接下來我們激活程式自帶的 HelloWorld 插件看看有什麼變化,激活後
plugins
字段變為:
Array
(
[activated] => Array
(
[HelloWorld] => Array
(
[handles] => Array
(
[admin/menu.php:navBar] => Array
(
[0] => Array
(
[0] => HelloWorld_Plugin
[1] => render
)
)
)
)
)
[handles] => Array
(
[admin/menu.php:navBar] => Array
(
[0] => Array
(
[0] => HelloWorld_Plugin
[1] => render
)
)
)
)
可以看出,激活插件後,程式根據插件的激活函數
public static function activate()
{
Typecho_Plugin::factory('admin/menu.php')->navBar = array('HelloWorld_Plugin', 'render');
}
系統在資料庫中将
HelloWorld
插件與
('admin/menu.php')->navBar()
接口作了關聯,
而具體關聯的則是
HelloWorld_Plugin
類的
render
函數。
其實到這裡大家也能看出個大概,我們通路系統背景的時候,當執行到
<?php Typecho_Plugin::factory('admin/menu.php')->navBar(); ?>
這句代碼時:
- 從資料庫
字段裡檢索,檢索到plugins
下挂載了一個插件,具體為[admin/menu.php:navBar]
HelloWorld_Plugin
函數,系統執行之并輸出render
在背景的導航欄。HelloWorld
- 那麼如果檢索不到有任何插件挂載呢,程式不執行任何動作并執行下邊的代碼,這也就是為什麼在分析系統流程時可以直接将插件接口的代碼略過的原因。
整個程式中關鍵的地方設定了很多類似的插件接口,友善通過編寫插件而不修改程式源代碼來完成我們特定的功能,設定插件接口的方法有兩種:
- 一種是
,在Typecho_Plugin::factory
中定義var/Typecho/Plugin.php
- 另一種是
, 在$this->pluginHandle()
var/Typecho/Widget.php
第二種是可以傳遞參數的接口,這個以後再說。
最後不禁有人要問,程式中設定這麼多接口,即使一個插件也沒安裝也要挨個執行嗎,效率得多低?
答案是肯定的,必須得執行,不過資料庫也隻讀取一次,然後存在記憶體裡,以後的每次查詢都是在記憶體對比,多執行兩行php代碼基本沒效率影響。具體速度咋樣,用過 wp 的你懂的~~
下一節,根據具體接口,示範插件編寫~