勾子技術DedeCms V5.3最大的改變之一,可能大家不大理解勾子這名稱,說具體些,在DedeCms裏有很多模板調用標籤,實際上,這些標籤是通過解析後,按不同名稱和屬 性返回不同內容來替代的,在不使用模板引擎的情況下,一個函數調用就可以認爲是勾子的一種體現,這也是一些論壇程序的做法,但這種做法始終需要在覈心一些 文件加入一些代碼,即使是最簡單的代碼,對升級顯然是有一定麻煩的,而DedeCms V5.3的勾子技術則改變了這種做法,它的原理與一些框架的MVC機制類似,不過它不是動態產生觸發器,而是動態解析標籤。
什麼是動態解析標籤?簡單的來說就是模板裏存在什麼標記就調用什麼代碼去解析,這樣不必要載入一些多餘的代碼,而且擴展更加靈活,在具體說明前,先用一個例子簡單說明DedeCms模板引擎的使用。
以下示例代碼可以放在安裝了dedecms系統的根目錄中使用。
以下爲引用的內容:
- <?php
- //引入必須文件
- require_once(dirname(__FILE__)."/include/commin.inc.php");
- require_once(dirname(__FILE__)."/include/channelunit.func.php");
- require_once(dirname(__FILE__)."/include/dedetag.class.php");
- //初始化模板類
- $dtp = new DedeTagParse();
- $dtp->SetNameSpace("dede","{","}");
- //引用當前類([1]這裏爲空,後面會說明用途)
- $dtp->refObj = null;
- //載入模板
- $dtp->LoadTemplet($filename);
- //動態解析 include/taglib 裏的標籤 [2]
- MakeOneTag($dtp, null);
- //解析系統標籤,顯示內容
- $dtp->Display();
- //類似方法:GetResult() 獲得解析後的HTML,SaveTo($filename)保存爲文件
- ?
-
在以上例子中,比較不好理解的是兩個 null,其實如果在類中調用這模板類,通常表示爲 $this
具體原因需要分析 channelunit.func.php 裏的
MakeOneTag(&$dtp,&$refObj)
這個函數的第一個參數不用說都知道是模板類本身的對象實例,如$refObj就是引入這個模板類的類,在Dedecms中,凡是 include/arc. 開頭的文件都是這種文檔解析類的具體功能類。
它的具體代碼如下:
以下爲引用的內容:
- function MakeOneTag(&$dtp,&$refObj)
- {
- $alltags = array();
- //讀取自由調用tag列表
- $dh = dir(DEDEINC.'/taglib');
- while($filename = $dh->read())
- {
- if(ereg("/.lib/.",$filename))
- {
- $alltags[] = str_replace('.lib.php','',$filename);
- }
- }
- $dh->Close();
- //遍歷tag元素
- if(!is_array($dtp->CTags))
- {
- return '';
- }
- foreach($dtp->CTags as $tagid=>$ctag)
- {
- $tagname = $ctag->GetName();
- //解析通用的 field 標籤 [1]*
- if($tagname=='field')
- {
- $vname = $ctag->GetAtt('name');
- if(isset($refObj->Fields[$vname]))
- {
- $dtp->Assign($tagid, $refObj->Fields[$vname]);
- }
- else if( isset( $this->TypeLink->TypeInfos[$vname] ) )
- {
- $dtp->Assign($tagid, $this->TypeLink->TypeInfos[$vname]);
- }
- continue;
- }
- //同名標記(兼容舊版)處理
- if(ereg("^(artlist|likeart|hotart|imglist|imginfolist|coolart|specart|autolist)$",$tagname))
- {
- $tagname='arclist';
- }
- if($tagname=='friendlink')
- {
- $tagname='flink';
- }
- //給不同的標記調用不同的解析文件 [2]*
- if(in_array($tagname,$alltags))
- {
- $filename = DEDEINC.'/taglib/'.$tagname.'.lib.php';
- include_once($filename);
- $funcname = 'lib_'.$tagname;
- $dtp->Assign($tagid,$funcname($ctag,$refObj));
- }
- }
- }
-
以上代碼的重點就是 [1] [2] 標註的地方
[1]是解析文檔中field標籤,這個標籤對於文檔類中,都必使用 var Fields; 數組來表示這些通用文檔字段,但對於不同模板,它的值也是可變的。
[2]就是勾子技術的關鍵,給field以及系統標記以外的標記調用不同的具體解析代碼,這裏規定了這些代碼必須放在include/taglib文件夾內,名稱爲“標記名.lib.php”,而這個文件裏定義的接口函數格式爲:
以下爲引用的內容:
- <?php
- if(!defined('DEDEINC'))
- {
- exit("Request Error!");
- }
- function lib_標記名稱(&$ctag,&$refObj)
- {
- global $dsql,$envs;
- //屬性處理
- $attlist="row|12,titlelen|24";
- FillAttsDefault($ctag->CAttribute->Items,$attlist);
- extract($ctag->CAttribute->Items, EXTR_SKIP);
- $revalue = '';
- //你需編寫的代碼,不能用echo之類語法,把最終返回值傳給$revalue
- //------------------------------------------------------
- $revalue = 'Hello Word!';
- //------------------------------------------------------
- return $revalue;
- }
- ?>
-
到這裏就完全揭開了DedeCms V5.3勾子技術的真正面目,上面還有一個沒交待清楚的是
“$dtp->refObj = null;” 這個地方,其實對於Dedecms的文檔解析類,100%都是面向對象的,它在類裏通常是寫爲
“$this->dtp->refObj = $this;” 這個對象正是 function lib_標記名稱(&$ctag,&$refObj) 裏的第二個參數,說到這裏,有點明白它的作用了吧,簡單的來說就是在接口函數裏獲取當前解析類的一些相關信息,這是相當有用的。