PHPliB類詳解
自已的BLOG空間打不開了,放些資料在這。
<?php??
/*??
* PHPlib模板7.4中文版(不足之處還請各位指正)??
* (C) Copyright 1999-2000 NetUSE GmbH??
* Kristian Koehntopp??
* 彭贊群注釋于2004年6月,QQ:9537075 TEL:13787877670??
* Email:mylovepzq@163.com??
*/??
/*這里是定義類Template*/??
class Template??
{? ?
/* 如果設置了,則輸出參數 */??
var $classname = "Template";??
var $debug = false; //是否調試??
var $root = ".";//root為模板文件的存放目錄??
var $file = array(); //包含了所有的模板文件名和模板名的數組??
var $varkeys = array(); //存放文本元素的鍵名??
var $varvals = array(); //存放文本元素的值??
var $unknowns = "remove";? ?
/* "remove" => 刪除未定義的變量 "comment" => 將未定義的變量變成注釋 "keep" => 保留未定義的變量 */??
var $halt_on_error = "yes";??
/* "yes" => 退出 "report" => 報告錯誤,繼續運行* "no" => 忽略錯誤*/??
var $last_error = "";??
/* 上一次的錯誤保存在這里 */??
/* public: 構造函數??
* root: 模板目錄??
* unknowns: 如何處理未知的變量(譯者:變量定義為{ name })??
*/??
/*這里是定義函數Template*/??
function Template($root = ".", $unknowns = "remove")? ?
{? ?
if ($this->debug & 4)? ?
{? ?
echo "<p><b>模板:</b> root = $root, unknowns = $unknowns</p>\n";??
}??
$this->set_root($root);//默認將文件目錄設置為相同的目錄??
$this->set_unknowns($unknowns);//unknowns默認設置為"remove"??
}??
/*這里是函數set_root*/??
function set_root($root)??
{? ?
if ($this->debug & 4)? ?
{? ?
echo "<p><b>設置根目錄:</b> root = $root</p>\n";??
}??
if (!is_dir($root))??
{? ?
$this->halt("設置根目錄: $root 不是一個無效的目錄.");??
return false;??
}??
$this->root = $root;??
return true;??
}??
//這里是函數set_unknowns,即對未知變量的處理??
function set_unknowns($unknowns = "remove")??
{? ?
if ($this->debug & 4)??
{? ?
echo "<p><b>未知的:</b> 未知 = $unknowns</p>\n";??
}??
$this->unknowns = $unknowns;??
}??
/*這里是函數set_file.......................................................*/??
//該方法在數組file中根據$varname提供的鍵名加入值??
function set_file($varname, $filename = "")??
{? ?
if (!is_array($varname))//如果varname是數組??
{? ?
if ($this->debug & 4)??
{? ?
echo "<p><b>設置文件:</b> (with scalar) varname = $varname, filename = $filename</p>\n";??
}??
if ($filename == "")//如果文件名為空,輸出錯誤??
{? ?
$this->halt("設置文件:變量名 $varname 文件名是空的.");??
return false;??
}??
$this->file[$varname] = $this->filename($filename);??
}? ?
else??
{? ?
reset($varname);//將varname的鍵名作為file數組的鍵名??
//將鍵名對應的值作為file數組的值??
while(list($v, $f) = each($varname))??
{? ?
if ($this->debug & 4)??
{? ?
echo "<p><b>set_file:</b> (with array) varname = $v, filename = $f</p>\n";??
}??
if ($f == "")??
{? ?
$this->halt("set_file: For varname $v filename is empty.");??
return false;??
}??
$this->file[$v] = $this->filename($f);??
}??
}??
return true;??
}??
//該方法取出某個父模板文件中的一個子模板??
//將其作為塊來加載??
//并用另外一個模板變量取代之??
/* public: set_file(array $filelist)??
* comment: 設置多個模板文件??
* filelist: (句柄,文件名)數組??
* public: set_file(string $handle, string $filename)??
* comment: 設置一個模板文件??
* handle: 文件的句柄??
* filename: 模板文件名??
*/??
function set_block($parent, $varname, $name = "") {? ?
if ($this->debug & 4) {? ?
echo "<p><b>set_block:</b> parent = $parent, varname = $varname, name = $name</p>\n";??
}??
if (!$this->loadfile($parent)) {? ?
$this->halt("set_block: unable to load $parent.");??
return false;??
}??
if ($name == "") {? ?
$name = $varname;//如果沒有指定模板變量的值就用子模板名作為模板變量名??
}??
$str = $this->get_var($parent);??
$reg = "/[ \t]*<!--\s+BEGIN $varname\s+-->\s*?\n?(\s*.*?\n?)\s*<!--\s+END $varname\s+-->\s*?\n?/sm";??
preg_match_all($reg, $str, $m);??
$str = preg_replace($reg, "{ " . "$name }", $str);??
$this->set_var($varname, $m[1][0]);??
$this->set_var($parent, $str);??
return true;??
}??
//該方法向Varname和varkeys數組中添加新的鍵一值對??
/* public: set_var(array $values)??
* values: (變量名,值)數組??
* public: set_var(string $varname, string $value)??
* varname: 將被定義的變量名??
* value: 變量的值??
*/??
function set_var($varname, $value = "", $append = false) {? ?
if (!is_array($varname))//如果不是陣列??
{? ?
if (!empty($varname)) //如果是空的??
{? ?
if ($this->debug & 1) {? ?
printf("<b>set_var:</b> (with scalar) <b>%s</b> = ’%s’<br>\n", $varname, htmlentities($value));??
}??
$this->varkeys[$varname] = "/".$this->varname($varname)."/";??
if ($append && isset($this->varvals[$varname])) {? ?
$this->varvals[$varname] .= $value;??
} else {? ?
$this->varvals[$varname] = $value;??
}??
}??
} else {? ?
reset($varname);??
while(list($k, $v) = each($varname)) {? ?
if (!empty($k)) {? ?
if ($this->debug & 1) {? ?
printf("<b>set_var:</b> (with array) <b>%s</b> = ’%s’<br>\n", $k, htmlentities($v));??
}??
$this->varkeys[$k] = "/".$this->varname($k)."/";??
if ($append && isset($this->varvals[$k])) {? ?
$this->varvals[$k] .= $v;??
} else {? ?
$this->varvals[$k] = $v;??
}??
}??
}??
}??
}??
//定義函數clear_var??
function clear_var($varname) {? ?
if (!is_array($varname))//如果varname不是陣列??
{? ?
if (!empty($varname)) //如果是空的??
{? ?
if ($this->debug & 1) {? ?
printf("<b>clear_var:</b> (with scalar) <b>%s</b><br>\n", $varname);??
}??
$this->set_var($varname, "");??
}??
} else {? ?
reset($varname);??
while(list($k, $v) = each($varname)) {? ?
if (!empty($v)) {? ?
if ($this->debug & 1) {? ?
printf("<b>clear_var:</b> (with array) <b>%s</b><br>\n", $v);??
}??
$this->set_var($v, "");??
}??
}??
}??
}??
/*這里是函數unset_var,刪除變量的定義*/??
function unset_var($varname) {? ?
if (!is_array($varname)) {? ?
if (!empty($varname)) {? ?
if ($this->debug & 1) {? ?
printf("<b>unset_var:</b> (with scalar) <b>%s</b><br>\n", $varname);??
}??
unset($this->varkeys[$varname]);??
unset($this->varvals[$varname]);??
}??
} else {? ?
reset($varname);??
while(list($k, $v) = each($varname)) {? ?
if (!empty($v)) {? ?
if ($this->debug & 1) {? ?
printf("<b>unset_var:</b> (with array) <b>%s</b><br>\n", $v);??
}??
unset($this->varkeys[$v]);??
unset($this->varvals[$v]);??
}??
}??
}??
}??
//將模板文件中的變化內容替換成確定內容的操作,實現數據和顯示的分離??
function subst($varname) {? ?
$varvals_quoted = array();??
if ($this->debug & 4) {? ?
echo "<p><b>subst:</b> varname = $varname</p>\n";??
}??
if (!$this->loadfile($varname)) //裝載模板文件,如果出錯就停止??
{? ?
$this->halt("subst: unable to load $varname.");??
return false;??
}??
reset($this->varvals);??
while(list($k, $v) = each($this->varvals)) {? ?
$varvals_quoted[$k] = preg_replace(array(’/\\\\/’, ’/\$/’), array(’\\\\\\’, ’\\\\$’), $v);??
}??
//讀入文件內容到字符串中并在下行對已知鍵值進行替換并返回結果??
$str = $this->get_var($varname);??
$str = preg_replace($this->varkeys, $varvals_quoted, $str);??
return $str;??
}??
//同subst,只是直接輸出結果??
function psubst($varname) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>psubst:</b> varname = $varname</p>\n";??
}??
print $this->subst($varname);??
return false;??
}??
//將varname代表的一個或多個文件中的內容完成替換??
//存放在target為鍵值的varvals數組無素中或追加到其后??
//返回值和sub相同??
function parse($target, $varname, $append = false) {? ?
if (!is_array($varname)) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>parse:</b> (with scalar) target = $target, varname = $varname, append = $append</p>\n";??
}??
$str = $this->subst($varname);??
if ($append) {? ?
$this->set_var($target, $this->get_var($target) . $str);??
} else {? ?
$this->set_var($target, $str);??
}??
} else {? ?
reset($varname);??
while(list($i, $v) = each($varname)) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>parse:</b> (with array) target = $target, i = $i, varname = $v, append = $append</p>\n";??
}??
$str = $this->subst($v);??
if ($append) {? ?
$this->set_var($target, $this->get_var($target) . $str);??
} else {? ?
$this->set_var($target, $str);??
}??
}??
}??
if ($this->debug & 4) {? ?
echo "<p><b>parse:</b> completed</p>\n";??
}??
return $str;??
}??
//同parse方法,只是該方法將結果輸出??
function pparse($target, $varname, $append = false) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>pparse:</b> passing parameters to parse...</p>\n";??
}??
print $this->finish($this->parse($target, $varname, $append));??
return false;??
}??
//返回所有的鍵一值對中的值所組成的數組??
function get_vars() {? ?
if ($this->debug & 4) {? ?
echo "<p><b>get_vars:</b> constructing array of vars...</p>\n";??
}??
reset($this->varkeys);??
while(list($k, $v) = each($this->varkeys)) {? ?
$result[$k] = $this->get_var($k);??
}??
return $result;??
}??
//根據鍵名返回對應的鍵一值勤對應的值??
function get_var($varname) {? ?
if (!is_array($varname)) //如果不是陣列??
{? ?
if (isset($this->varvals[$varname])) //如果變量不存在??
{? ?
$str = $this->varvals[$varname];??
} else {? ?
$str = "";??
}??
if ($this->debug & 2) {? ?
printf ("<b>get_var</b> (with scalar) <b>%s</b> = ’%s’<br>\n", $varname, htmlentities($str));??
}??
return $str;??
} else {? ?
reset($varname);??
while(list($k, $v) = each($varname)) {? ?
if (isset($this->varvals[$v])) {? ?
$str = $this->varvals[$v];??
} else {? ?
$str = "";??
}??
if ($this->debug & 2) {? ?
printf ("<b>get_var:</b> (with array) <b>%s</b> = ’%s’<br>\n", $v, htmlentities($str));??
}??
$result[$v] = $str;??
}??
return $result;??
}??
}??
//如果加載文件失敗,返回錯誤并停止??
function get_undefined($varname) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>get_undefined:</b> varname = $varname</p>\n";??
}??
if (!$this->loadfile($varname)) {? ?
$this->halt("get_undefined: unable to load $varname.");??
return false;??
}??
preg_match_all("/{ ([^ \t\r\n }]+) }/", $this->get_var($varname), $m);??
$m = $m[1];??
//如果無法找到匹配的文本,返回錯誤??
if (!is_array($m)) {? ?
return false;??
}??
//如果能找到大括號中的非空字符,則將其值作為鍵值,組成一個新的數組??
reset($m);??
while(list($k, $v) = each($m)) {? ?
if (!isset($this->varkeys[$v])) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>get_undefined:</b> undefined: $v</p>\n";??
}??
$result[$v] = $v;??
}??
}??
//如是該數組不為空就返回該數組,否則就返回錯誤??
if (count($result)) {? ?
return $result;??
} else {? ?
return false;??
}??
}??
//完成對str的最后的處理工作,利用類的屬性unknowns來確定對模板中無法處理的動態部分的處理方法??
function finish($str) {? ?
switch ($this->unknowns) {? ?
case "keep": //保持不變??
break;??
case "remove": //刪除所有的非控制符??
$str = preg_replace(’/{ [^ \t\r\n }]+ }/’, "", $str);??
break;??
case "comment"://將大括號中的HTML注釋??
$str = preg_replace(’/{ ([^ \t\r\n }]+) }/’, "<!-- Template variable \\1 undefined -->", $str);??
break;??
}??
return $str;??
}??
//將參數變量對誚的數組中的值處理后輸出??
function p($varname) {? ?
print $this->finish($this->get_var($varname));??
}??
//將參數變量對應的數組中的值處理后返回??
function get($varname) {? ?
return $this->finish($this->get_var($varname));??
}??
//檢查并補充給定的文件名??
function filename($filename) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>filename:</b> filename = $filename</p>\n";??
}??
if (substr($filename, 0, 1) != "/")? ?
//如果文件名不是以斜杠開頭,則表示是相對路徑,將其補充為完整的絕對路徑? ?
{? ?
$filename = $this->root."/".$filename;??
}??
//如果文件不存在??
if (!file_exists($filename)) {? ?
$this->halt("filename: file $filename does not exist.");??
}??
return $filename;//返回文件名??
}??
//對變量名進行處理,將正則表達式中的敏感字符變為轉義字符,并在變量名兩端加上大括號??
function varname($varname) {? ?
return preg_quote("{ ".$varname." }");??
}??
//該方法根據varname加載文件到鍵一值對中??
function loadfile($varname) {? ?
if ($this->debug & 4) {? ?
echo "<p><b>loadfile:</b> varname = $varname</p>\n";??
}??
if (!isset($this->file[$varname])) //如果沒有指定就返加錯誤??
{? ?
// $varname does not reference a file so return??
if ($this->debug & 4) {? ?
echo "<p><b>loadfile:</b> varname $varname does not reference a file</p>\n";??
}??
return true;??
}??
if (isset($this->varvals[$varname]))//如果已經加載了varname為名柄的文件,直接返回真值??
{? ?
if ($this->debug & 4) {? ?
echo "<p><b>loadfile:</b> varname $varname is already loaded</p>\n";??
}??
return true;??
}??
$filename = $this->file[$varname];//句柄有效則取出對應的文件名??
$str = implode("", @file($filename));//將文件的每一行連接成一個字符串??
if (empty($str)) //字符串空說明文件空或者不存在,返回錯誤??
{? ?
$this->halt("loadfile: While loading $varname, $filename does not exist or is empty.");??
return false;??
}??
if ($this->debug & 4) {? ?
printf("<b>loadfile:</b> loaded $filename into $varname<br>\n");??
}??
$this->set_var($varname, $str);//如果文件不為空,用$varname作為句柄,str為變量名??
//向鍵值對中添加新的鍵值??
return true;??
}??
//將分析結果保存到文件中去??
??function savetofile ($dir,$varname){? ?
? ?$data=$this->finish($this->get_var($varname));??
? ?$fp=fopen($dir,"w+");??
? ?fwrite($fp,$data);??
??}??
??//清除已賦值數組??
? ?function renew(){? ?
? ? $this->varkeys=array();??
? ? $this->varvals=array();??
? ? $this->file=array();??
? ? }??
//出錯提示并終止程序運行??
function halt($msg) {? ?
$this->last_error = $msg;??
if ($this->halt_on_error != "no") {? ?
$this->haltmsg($msg);??
}??
if ($this->halt_on_error == "yes") {? ?
die("<b>終止.</b>");??
}??
return false;??
}??
//出錯提示??
function haltmsg($msg) {? ?
printf("<b>模板錯誤:</b> %s<br>\n", $msg);??
}??
}??
?>
SOLO
PHPLIB Template類的使用的.誠然,網絡上已經很多相關的話題了,但據我觀察,中文的資料實在不多,且大多是講的太籠統,沒能全面闡述它的用法,即使看了還是一知半解.所以本文就期望通過對它的比較全面的介紹,讓你能達到入門的水平.
何謂"模板"技術
我們的最初觀察是將界面和實現代碼分離開來,這樣做的目的是將美工和程序員的工作分離開來.PHP的一個優點是可以把PHP代碼嵌入HTML里面,這樣你就不必再把大段HTML代碼用函數print()輸出來.
print("<table border=0 cellspacing=1 cellpadding=2 width=100%>");
print("<tr>");
print("<td>");
print("我愛你 kiki");
print("</td>");
print("</tr>");
print("</table>");
這段代碼對界面維護來說是相當困難的,除非程序員做這樣事情且他對樣式表,HTML非常精通.取而代之的我們用
<table border=0 cellspacing=1 cellpadding=2 width=100%>
? ? <tr>
? ?? ???<td>
? ?? ?? ?? ?<?php print("我愛你 kiki ");?>
? ?? ???</td>
? ? </tr>
</table>
這樣,做美工設計的只要不碰PHP代碼,就可以很方便地改變這個表格的樣式,如果使用dreamweaver等所見即所的工具,將會更加方便.
現在的一個問題是,如果美工正在修改的話,程序員仍需要把這個文件取回來,才能改變里面的PHP代碼,修改完后再交給美工,這樣循環往復,往往要花費大量的時間和精力,如果你所在公司是采取這種模式的話,恐怕老板為了節省時間,會把很多界面設計也交給程序員來做,畢竟他不會讓你們任何一個閑座著等待.作為程序員的你此時可能會夢想:如果程序員只要負責寫程序代碼,不理會令人煩躁的界面,那就太好了.
或許Fast Template誕生那刻起(我不敢確定它是最早的PHP模板處理類,但用起來確實很方便),你的夢想就幾近實現.策劃們把東西交給你,當然里面的元素都寫好了的,形如以下tpl.html
<table border=0 cellspacing=1 cellpadding=2 width=100%>
? ? <tr>
? ?? ???<td>
? ?? ?? ?? ?我愛你{MY_LOVE}
? ?? ???</td>
? ? </tr>
</table>
你只需要在程序里給這些元素(MY_LOVE)賦值就行了tpl.php
? ? $tpl->assign("MY_LOVE", "kiki");
你基本上不用管這些元素的樣式(比如字體,寬度,高度等),所在位置,甚至這些元素將來可能不再使用了.與此同時,美工那邊把元素放進一個HTML頁面里(這個頁面就是我們所說的"模板"),他也不用擔心會不小心把你的程序給搞壞了.然后做完后交給一個專門負責程序和美工結合的人(當然在國內也是程序員做這樣事情),他很可能只需要很小的幾個修改就可以把兩者結合的很好.這樣對你,對美工,都大大提高了工作效率,老板自然也會很高興啦.
所以我這里所說的"模板"技術,就是可以將程序和美工分離的技術,注意不是邏輯抽象層與表現層的分離.一來,那樣將會讓人不知所云,因為"邏輯抽象"這四個字就已經太抽象了,且表現層并只是美工所做的模板.所以,很多人試圖把Fast Template,PHPLIB Template兩個與Smarty相比較,在我看來,這是明顯不對的.
PHPLIB Template類也是一個用PHP代碼處理模板的一個類.也是本文要將要闡述的一個模板類.同上面講的一樣,它能把模板中的"元素"替換為你為它設定的值",且處理的很很好,也容易擴展,由于使用了preg_函數,所以速度也比較快.很多人都會提出一個意見:使用模板會讓你的代碼運行的更慢,確實是這樣的,如果你使用嵌入式寫法,會快一些,如果把PHP連同HTML全部寫入PHP里(用 print("<html標簽>"); ),可能會更快.但如果綜合考慮整個項目的開發效率,以及后期維護性的話,這些代價是可以承受的,而且慢也不會慢哪里去,真正的問題所在可能是你的模板實在是太大了.當然,你也可以改進這個模板類,讓它運行的更快.
提起PHPLIB Template,很多人自然會聯想起Fast Template來,我也不例外,因為兩者很多地方都很相近.對此,很多人都做了比較,在這里我就不再詳述了,或許王晨的這篇文章值得一看: 在PHP世界中選擇最合適的模板
獲取
可以從這里下載 [url]http://www.sanisoft.com/phplib/download.phpPHPLIB[/url] ,然后從壓縮包中php目錄下取出template.inc,就可以供我們使用了.
文檔
英文文檔 [url]http://www.sanisoft.com/phplib/manual/template.php[/url]
我翻譯的中文文檔(僅做參考) [url]http://www.4kiki.net/php_lib_template/[/url]
還有網上的很多資源,可以通過google搜索得到.
從類里面注釋可以知道,最新版本是2002/07/11 22:29:51的1.12版,所以,你或許需要修改一些東西,在你懂的前提下.我們還可以下載它的PEAR集成版本([url]http://pear.php.net/package/HTML_Template_PHPLIB/download)[/url] , 不過你的PHP版本需要在4.3.0以上.
何謂"模板"技術
我們的最初觀察是將界面和實現代碼分離開來,這樣做的目的是將美工和程序員的工作分離開來.PHP的一個優點是可以把PHP代碼嵌入HTML里面,這樣你就不必再把大段HTML代碼用函數print()輸出來.
print("<table border=0 cellspacing=1 cellpadding=2 width=100%>");
print("<tr>");
print("<td>");
print("我愛你 kiki");
print("</td>");
print("</tr>");
print("</table>");
這段代碼對界面維護來說是相當困難的,除非程序員做這樣事情且他對樣式表,HTML非常精通.取而代之的我們用
<table border=0 cellspacing=1 cellpadding=2 width=100%>
? ? <tr>
? ?? ???<td>
? ?? ?? ?? ?<?php print("我愛你 kiki ");?>
? ?? ???</td>
? ? </tr>
</table>
這樣,做美工設計的只要不碰PHP代碼,就可以很方便地改變這個表格的樣式,如果使用dreamweaver等所見即所的工具,將會更加方便.
現在的一個問題是,如果美工正在修改的話,程序員仍需要把這個文件取回來,才能改變里面的PHP代碼,修改完后再交給美工,這樣循環往復,往往要花費大量的時間和精力,如果你所在公司是采取這種模式的話,恐怕老板為了節省時間,會把很多界面設計也交給程序員來做,畢竟他不會讓你們任何一個閑座著等待.作為程序員的你此時可能會夢想:如果程序員只要負責寫程序代碼,不理會令人煩躁的界面,那就太好了.
或許Fast Template誕生那刻起(我不敢確定它是最早的PHP模板處理類,但用起來確實很方便),你的夢想就幾近實現.策劃們把東西交給你,當然里面的元素都寫好了的,形如以下tpl.html
<table border=0 cellspacing=1 cellpadding=2 width=100%>
? ? <tr>
? ?? ???<td>
? ?? ?? ?? ?我愛你{MY_LOVE}
? ?? ???</td>
? ? </tr>
</table>
你只需要在程序里給這些元素(MY_LOVE)賦值就行了tpl.php
? ? $tpl->assign("MY_LOVE", "kiki");
你基本上不用管這些元素的樣式(比如字體,寬度,高度等),所在位置,甚至這些元素將來可能不再使用了.與此同時,美工那邊把元素放進一個HTML頁面里(這個頁面就是我們所說的"模板"),他也不用擔心會不小心把你的程序給搞壞了.然后做完后交給一個專門負責程序和美工結合的人(當然在國內也是程序員做這樣事情),他很可能只需要很小的幾個修改就可以把兩者結合的很好.這樣對你,對美工,都大大提高了工作效率,老板自然也會很高興啦.
所以我這里所說的"模板"技術,就是可以將程序和美工分離的技術,注意不是邏輯抽象層與表現層的分離.一來,那樣將會讓人不知所云,因為"邏輯抽象"這四個字就已經太抽象了,且表現層并只是美工所做的模板.所以,很多人試圖把Fast Template,PHPLIB Template兩個與Smarty相比較,在我看來,這是明顯不對的.
PHPLIB Template類也是一個用PHP代碼處理模板的一個類.也是本文要將要闡述的一個模板類.同上面講的一樣,它能把模板中的"元素"替換為你為它設定的值",且處理的很很好,也容易擴展,由于使用了preg_函數,所以速度也比較快.很多人都會提出一個意見:使用模板會讓你的代碼運行的更慢,確實是這樣的,如果你使用嵌入式寫法,會快一些,如果把PHP連同HTML全部寫入PHP里(用 print("<html標簽>"); ),可能會更快.但如果綜合考慮整個項目的開發效率,以及后期維護性的話,這些代價是可以承受的,而且慢也不會慢哪里去,真正的問題所在可能是你的模板實在是太大了.當然,你也可以改進這個模板類,讓它運行的更快.
提起PHPLIB Template,很多人自然會聯想起Fast Template來,我也不例外,因為兩者很多地方都很相近.對此,很多人都做了比較,在這里我就不再詳述了,或許王晨的這篇文章值得一看: 在PHP世界中選擇最合適的模板
獲取
可以從這里下載 [url]http://www.sanisoft.com/phplib/download.phpPHPLIB[/url] ,然后從壓縮包中php目錄下取出template.inc,就可以供我們使用了.
文檔
英文文檔 [url]http://www.sanisoft.com/phplib/manual/template.php[/url]
我翻譯的中文文檔(僅做參考) [url]http://www.4kiki.net/php_lib_template/[/url]
還有網上的很多資源,可以通過google搜索得到.
從類里面注釋可以知道,最新版本是2002/07/11 22:29:51的1.12版,所以,你或許需要修改一些東西,在你懂的前提下.我們還可以下載它的PEAR集成版本([url]http://pear.php.net/package/HTML_Template_PHPLIB/download)[/url] , 不過你的PHP版本需要在4.3.0以上.
2005-11-8 23:19SOLO
一個封裝很好的類對使用者(可能不是開發者本人)來說,最大的好處就是,你無需知道類內部是怎么運作的,只需知道如何利用它提供的接口做你想做的事情即可.所以,本文不打算具體講述PHPLIB Template(以下簡稱Template)是如何將"元素"轉換成"值"的,你需要了解的是"它能這樣做",而不是"它為什么能這樣做".
好了,下面我們就開始它的第一個應用了.
先在我們要測試的網站的目錄下建兩個文件夾inc和template.目錄inc下放引用文件,比如類庫,函數庫等,這里我們就把template.inc放如該目錄下.tempate下放模板文件,我們先建一個模板文件first.html,內容如下
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第一個模板文件 </TITLE>
</HEAD>
<BODY>
真想對你說:我愛你 {lover} ,但我卻不敢說,因為我知道你愛的人是 {man}.
<P>
<font color="#0000FF">{author}</font> 于 {date}
</BODY>
</HTML>
用inc,template命名文件目錄,都是我的個人習慣,你完全可以采取不同的方式.我用擴展名為.html的名稱命名模板文件,是為了方便美工用frontpage或者dreamweaver修改,但這完全取決于你自己的習慣.
first.html模板中的{lover},{man},{author}可以稱為"模板變量",用花括號({})把變量名稱括住即組成一個模板變量.模板變量就是模板元素的一種。你可能會擔心它的命名問題,其實除了空格(" "),回車換行("\r", "\n"),tab(\t)外它都被視為是正確的.所以
{your-lover}
也是正確的.這點有時可能會令你很痛苦,因為模板里的有些javascript代碼可能無意間變沒有了,比如
if(a>b){document.write("i love u");}
中的
{document.write("i love u");}
也被視為一個變量了.上面的代碼在你選的模板處理方式下,可能會變成if(a>b){},從而導致javascript錯誤.為什么會"變沒"了呢?稍后將做解釋.
上面我們定義的三個變量{lover},{man},{author}的原因是,我們想隨時改變它們的值.下面我們就來做這個工作.新建first.php文件,內容如下:
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template", "keep"); //注1
//將整個文件讀進來
$tpl->set_file("main", "first.html"); //注2
//給文件中的模板變量賦值
$tpl->set_var("lover", "kiki"); //注3
$tpl->set_var("man", "ccterran"); //注4
$tpl->set_var("author", "iwind"); //注5
//完成替換
$tpl->parse("mains", "main"); //注6
//輸出替換的結果
$tpl->p("mains"); //注7
?>
瀏覽器中瀏覽這個文件,你就會發現輸出
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于 {date}
這一切正如我們所期望的(除了{date}).注1
$tpl = new Template("template", "keep");
是創建一個Template類的實例對象.它有兩個參數,都是可選的.
第一個參數是模板所在目錄,如果不設置則為"."(即當前目錄),由于我們剛才把模板文件first.html放到template下了,所以這里為template.注意它一般使用相對路徑,如果你用相對于根目錄(比如 /phplib/test/template)的路徑,就會出現
Template Error: set_root: /phplib/test/template is not a directory.
Halted.
的錯誤.
第二個參數是指定模板類對"未完成處理"變量的處理方式,所謂"未完成處理"指的是模板變量未賦值,塊未完成替換工作(下面一節將講到它),它有三個值可選,分別為"keep","comment","remove":
如果設為"keep",這些變量將原封不動的保留下來.
如果設為"comment",那么會在報錯的同時,將未完成處理的變量全部轉換成HTML的注釋.
如果設為"remove",未完成處理的變量便會被刪除(這也是默認的情況).
所以在上面的例子中,我指定的是"keep",于是{date}因為未賦值,所以還保留著.而缺省的情況下是"remove",所以,如果我這樣創建實例對象
$tpl = new Template("template", "remove");
或者
$tpl = new Template("template");
的話,輸出就變成了
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于
可以看出{date}被刪除了.如果是
$tpl = new Template("template", "comment");
它的結果將是
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于
看起來和"remove"方式一樣,但查看源文件,我們會發現
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第一個模板文件 </TITLE>
</HEAD>
<BODY>
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
<P>
<font color="#0000FF">iwind</font> 于 <!-- Template variable date undefined -->
</BODY>
</HTML>
其中有<!-- Template variable date undefined -->的錯誤信息,告訴我們date變量未定義(賦值).
用"comment"或許對程序的調試很有幫助.
我們再回頭看看
if(a>b){document.write("i love u");}
中
{document.write("i love u");}
會"變沒"的問題,是因為模板類視之為模板變量,但你沒有給它指定值(當然會沒有),且你沒有指定"keep"方式來處理未定義變量,所以它就被"remove"了.
所以在模板使用過程中應該多多注意這些問題.
注2是將一個模板文件加載進來,事實上你可以一次加載多個模板(在第四節將講到這個問題).你可以想象
$tpl->set_file("main", "first.html");
把"first.html"內容給變量"main"(盡管很多人稱之為"句柄",但本文決定不談"句柄"),所以"main"的值就變成模板的內容了,包含著那些模板變量.
注3,注4,注5,是給模板變量賦值.值是什么,你自然可以隨便定.比如你還可以
$tpl->set_var("lover", "kiki1");
$tpl->set_var("man", "ccterran1");
$tpl->set_var("author", "iwind_php");
你也可以一次完成給一列的變量賦值.這樣
$tpl->set_var(
array("lover"=>"kiki", "man"=>"ccterran", "author"=>"iwind")
);
如果你想設置一個變量的值為空的話,可以
$tpl->set_var("man", "");
或者
$tpl->set_var("man");
注6,是執行將上面$tpl->set_var給模板變量指定的值替換掉模板中的模板變量這個操作,第一個參數即為模板分析的結果,也可以視為一個變量.
當然注7的 $tpl->p("mains"); 就將模板分析的結果如你所愿的輸出啦.
喏,恭喜你,你的第一個模板類應用就完成了.你可能不小心弄錯了哪個地方,模板類默認情況下會自動打印出錯誤提示的,根據這些提示,你就很容易就可以找出問題所在,在第6節將會具體講到.
SOLO
好了,下面我們就開始它的第一個應用了.
先在我們要測試的網站的目錄下建兩個文件夾inc和template.目錄inc下放引用文件,比如類庫,函數庫等,這里我們就把template.inc放如該目錄下.tempate下放模板文件,我們先建一個模板文件first.html,內容如下
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第一個模板文件 </TITLE>
</HEAD>
<BODY>
真想對你說:我愛你 {lover} ,但我卻不敢說,因為我知道你愛的人是 {man}.
<P>
<font color="#0000FF">{author}</font> 于 {date}
</BODY>
</HTML>
用inc,template命名文件目錄,都是我的個人習慣,你完全可以采取不同的方式.我用擴展名為.html的名稱命名模板文件,是為了方便美工用frontpage或者dreamweaver修改,但這完全取決于你自己的習慣.
first.html模板中的{lover},{man},{author}可以稱為"模板變量",用花括號({})把變量名稱括住即組成一個模板變量.模板變量就是模板元素的一種。你可能會擔心它的命名問題,其實除了空格(" "),回車換行("\r", "\n"),tab(\t)外它都被視為是正確的.所以
{your-lover}
也是正確的.這點有時可能會令你很痛苦,因為模板里的有些javascript代碼可能無意間變沒有了,比如
if(a>b){document.write("i love u");}
中的
{document.write("i love u");}
也被視為一個變量了.上面的代碼在你選的模板處理方式下,可能會變成if(a>b){},從而導致javascript錯誤.為什么會"變沒"了呢?稍后將做解釋.
上面我們定義的三個變量{lover},{man},{author}的原因是,我們想隨時改變它們的值.下面我們就來做這個工作.新建first.php文件,內容如下:
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template", "keep"); //注1
//將整個文件讀進來
$tpl->set_file("main", "first.html"); //注2
//給文件中的模板變量賦值
$tpl->set_var("lover", "kiki"); //注3
$tpl->set_var("man", "ccterran"); //注4
$tpl->set_var("author", "iwind"); //注5
//完成替換
$tpl->parse("mains", "main"); //注6
//輸出替換的結果
$tpl->p("mains"); //注7
?>
瀏覽器中瀏覽這個文件,你就會發現輸出
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于 {date}
這一切正如我們所期望的(除了{date}).注1
$tpl = new Template("template", "keep");
是創建一個Template類的實例對象.它有兩個參數,都是可選的.
第一個參數是模板所在目錄,如果不設置則為"."(即當前目錄),由于我們剛才把模板文件first.html放到template下了,所以這里為template.注意它一般使用相對路徑,如果你用相對于根目錄(比如 /phplib/test/template)的路徑,就會出現
Template Error: set_root: /phplib/test/template is not a directory.
Halted.
的錯誤.
第二個參數是指定模板類對"未完成處理"變量的處理方式,所謂"未完成處理"指的是模板變量未賦值,塊未完成替換工作(下面一節將講到它),它有三個值可選,分別為"keep","comment","remove":
如果設為"keep",這些變量將原封不動的保留下來.
如果設為"comment",那么會在報錯的同時,將未完成處理的變量全部轉換成HTML的注釋.
如果設為"remove",未完成處理的變量便會被刪除(這也是默認的情況).
所以在上面的例子中,我指定的是"keep",于是{date}因為未賦值,所以還保留著.而缺省的情況下是"remove",所以,如果我這樣創建實例對象
$tpl = new Template("template", "remove");
或者
$tpl = new Template("template");
的話,輸出就變成了
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于
可以看出{date}被刪除了.如果是
$tpl = new Template("template", "comment");
它的結果將是
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
iwind 于
看起來和"remove"方式一樣,但查看源文件,我們會發現
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第一個模板文件 </TITLE>
</HEAD>
<BODY>
真想對你說:我愛你 kiki ,但我卻不敢說,因為我知道你愛的人是 ccterran.
<P>
<font color="#0000FF">iwind</font> 于 <!-- Template variable date undefined -->
</BODY>
</HTML>
其中有<!-- Template variable date undefined -->的錯誤信息,告訴我們date變量未定義(賦值).
用"comment"或許對程序的調試很有幫助.
我們再回頭看看
if(a>b){document.write("i love u");}
中
{document.write("i love u");}
會"變沒"的問題,是因為模板類視之為模板變量,但你沒有給它指定值(當然會沒有),且你沒有指定"keep"方式來處理未定義變量,所以它就被"remove"了.
所以在模板使用過程中應該多多注意這些問題.
注2是將一個模板文件加載進來,事實上你可以一次加載多個模板(在第四節將講到這個問題).你可以想象
$tpl->set_file("main", "first.html");
把"first.html"內容給變量"main"(盡管很多人稱之為"句柄",但本文決定不談"句柄"),所以"main"的值就變成模板的內容了,包含著那些模板變量.
注3,注4,注5,是給模板變量賦值.值是什么,你自然可以隨便定.比如你還可以
$tpl->set_var("lover", "kiki1");
$tpl->set_var("man", "ccterran1");
$tpl->set_var("author", "iwind_php");
你也可以一次完成給一列的變量賦值.這樣
$tpl->set_var(
array("lover"=>"kiki", "man"=>"ccterran", "author"=>"iwind")
);
如果你想設置一個變量的值為空的話,可以
$tpl->set_var("man", "");
或者
$tpl->set_var("man");
注6,是執行將上面$tpl->set_var給模板變量指定的值替換掉模板中的模板變量這個操作,第一個參數即為模板分析的結果,也可以視為一個變量.
當然注7的 $tpl->p("mains"); 就將模板分析的結果如你所愿的輸出啦.
喏,恭喜你,你的第一個模板類應用就完成了.你可能不小心弄錯了哪個地方,模板類默認情況下會自動打印出錯誤提示的,根據這些提示,你就很容易就可以找出問題所在,在第6節將會具體講到.
SOLO
PHPLIB Template入門系列 - 3 塊的應用
在上一節中,我們知道模板元素的一種:模板變量,并知道如何在程序中給它賦值,使之呈現我們想要的東西.這對一般的簡單網頁來說,或許就已經夠用了.現在我們設想一稍微復雜的一種情況,在template目錄下新建一個second.html模板文件,內容為:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD> <BODY>
下面是一個列表
<UL>
<li>張三 的成績是 82
<li>李四 的成績是 90
<li>王兒 的成績是 60
<li>麻子 的成績是 77
</UL>
</BODY>
</HTML>
上面的列表中列出了"張三","李四","王二","麻子"四人的成績.假設要用PHP代碼嵌入HTML的方式輸出的話,你可能是這樣寫的:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<?php
$result = mysql_query("SELECT username,score FROM my_tbl");
?>
<UL>
<?php
while ($row = mysql_fetch_array($result))
{
?>
<li><?=$row["username"]?> 的成績是 <?=$row["score"]?>
<?php
}
?>
</UL>
</BODY>
</HTML>
這樣寫很適合PHP新手,但你很快發現你或者美工改這個列表樣式的時候需要多么的小心翼翼,特別是美工,如果他不懂你寫得PHP代碼,那么他會終日生在恐懼之中!因為稍微的不小心,可能就會帶來程序的運行錯誤.而且如果他想把這個列表從一個地方移到另一個地方,也是相當不容易的.于是作為程序員的你不得不把美工(雖然你做的可能性更大)修飾過的頁面重新審查一次,無形中就造成費時費力。
現在好了,有了Template模板類,你可以把你的代碼從模板中抽取出來了.你可能會這樣修改second.html模板:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<li>{username1} 的成績是 {score1}
<li>{username2} 的成績是 {score2}
<li>{username3} 的成績是 {score3}
<li>{username4} 的成績是 {score4}
</UL>
</BODY>
</HTML>
顯然,你采取了一個良好的命名方式,用1,2,3..來表示每一行數據,然后你在你的程序里循環給這些變量賦值,也是不難的,比如:(second.php)
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "first.html");
//連接數據庫,選擇數據庫略
省略.....
//查詢結果
$result = mysql_query("SELECT username,score FROM my_tbl");
//給文件中的模板變量賦值
$i=0;
while ($row = $idb->fetch_array($result))
{
$i++;
$tpl->set_var("username" . $i, $row["username"]);
$tpl->set_var("score" . $i, $row["score"]);
}
//完成替換
$tpl->parse("mains", "main");
//輸出
$tpl->pparse("mains", "main");
?>
這樣你也能得到正確結果.在特殊情況下你或許需要這樣做.但Template提供了一個更方便的"大的模板變量",那就是塊.我之所以稱之為"大的模板變量",是因為它也可以視為可以包含其他模板變量的變量.形式如
<UL>
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
</UL>
即用<!-- BEGIN 塊名稱 -->和<!-- END 塊名稱 -->定義了一個名為list的塊,(注意:我在這里為了方便理解,只稱之為塊名稱).這個塊里面又包含一些HTML代碼(<li>等等)以及模板變量({username},{score}).
在講述如何用塊輸出列表之前,我們先談一下塊的定義格式.
首先<!-- BEGIN list -->和<!-- END list --> 都要各自為一行,亦即下面的塊的定義是錯誤的
1,
同行的 <!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
2,
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list --> 同行的
<!--和-->都是固定的,也就是說只能是兩個中劃線("-"),且它們與BEGIN list之間都至少有一個空(空格或tab),看下面的例子
<!--BEGIN list -->
<!-- BEGIN list-->
它們都是錯誤的塊的定義方法,因為第一個<!--與BEGIN之間至少應該有一個空,第二個-->與list之間至少有一個空.
BEGIN/END和list之間也應該有一個空格,注意是有且僅有一個空格,不能多也不能少.
塊的名稱建議你只使用字符,數字,下劃線以及它們的組合.
BEGIN和END兩個詞語都應該是大寫的。
好了,下面開始探討如何是這個塊變成一個列表.我們可以這樣
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "second.html");
//加載塊list
$tpl->set_block("main", "list", "lists");
//連接數據庫,選擇數據庫略
省略.....
//查詢結果
$result = mysql_query("SELECT username,score FROM my_tbl");
//給文件中的模板變量賦值
while ($row = $idb->fetch_array($result))
{
$tpl->set_var("username", $row["username"]);
$tpl->set_var("score", $row["score"]);
$tpl->parse("lists", "list", true);
}
//完成替換
$tpl->parse("mains", "main");
//輸出
$tpl->pparse("mains", "main");
?>
記住把你的數據庫連接寫在我省略的部分,就可以打印正確的結果,一如
下面是一個列表
張三 的成績是 82
李四 的成績是 90
王兒 的成績是 60
麻子 的成績是 77
可以看到在PHP代碼里有兩個東西
$tpl->set_block("main", "list", "lists"); //代碼1
$tpl->parse("lists", "list", true);
就不可思議的將整個塊循環輸出了.代碼1用來加載模板main中的塊list,并給其一個名字lists,list就是模板中的一個大變量,它的內容就是<li>{username} 的成績是 {score}即:
"list" = "<li>{username} 的成績是 {score}"
之所以用lists命名,是為了程序的可讀性,也就是說我很容易就知道XXXs是XXX塊的名稱.
使用set_block后,模板中的塊內容
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
就被lists代替了.于是我們的模板就變成了
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
{lists}
</UL>
</BODY>
</HTML>
塊變成了一個變量(lists)!下面只要將lists變量替換成我們想要的就行了.
代碼二所處的循環
while ($row = $idb->fetch_array($result))
{
$tpl->set_var("username", $row["username"]);
$tpl->set_var("score", $row["score"]);
$tpl->parse("lists", "list", true); //代碼2
}
每一次循環,兩個set_var分別給username,score賦值,然后"list"就變成了
"list" = "<li>具體的名字 的成績是 具體的分數"
代碼2就是將list分析后的內容賦給lists,這樣就完成了整個塊的分析.
parse第三個參數可以設置list中的值是直接存在lists里面,還是附加在原有值之后.我們這里設置為true,說明是附加在原有值之后,才得以每個list的值都會顯示出來.反之設為false的話,后面的值會覆蓋掉以前的值.最終的結果會是
下面是一個列表
麻子 的成績是 77
綜上所述,Template模板類的替換方式是:
1,用set_block將模板中的list塊(或者你命名的其他塊)替換成變量lists.
2,用set_var給list塊中的變量賦值
3,把賦值并執行替換后的list內容依次給lists
4,完成分析
在上一節中,我們知道模板元素的一種:模板變量,并知道如何在程序中給它賦值,使之呈現我們想要的東西.這對一般的簡單網頁來說,或許就已經夠用了.現在我們設想一稍微復雜的一種情況,在template目錄下新建一個second.html模板文件,內容為:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD> <BODY>
下面是一個列表
<UL>
<li>張三 的成績是 82
<li>李四 的成績是 90
<li>王兒 的成績是 60
<li>麻子 的成績是 77
</UL>
</BODY>
</HTML>
上面的列表中列出了"張三","李四","王二","麻子"四人的成績.假設要用PHP代碼嵌入HTML的方式輸出的話,你可能是這樣寫的:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<?php
$result = mysql_query("SELECT username,score FROM my_tbl");
?>
<UL>
<?php
while ($row = mysql_fetch_array($result))
{
?>
<li><?=$row["username"]?> 的成績是 <?=$row["score"]?>
<?php
}
?>
</UL>
</BODY>
</HTML>
這樣寫很適合PHP新手,但你很快發現你或者美工改這個列表樣式的時候需要多么的小心翼翼,特別是美工,如果他不懂你寫得PHP代碼,那么他會終日生在恐懼之中!因為稍微的不小心,可能就會帶來程序的運行錯誤.而且如果他想把這個列表從一個地方移到另一個地方,也是相當不容易的.于是作為程序員的你不得不把美工(雖然你做的可能性更大)修飾過的頁面重新審查一次,無形中就造成費時費力。
現在好了,有了Template模板類,你可以把你的代碼從模板中抽取出來了.你可能會這樣修改second.html模板:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<li>{username1} 的成績是 {score1}
<li>{username2} 的成績是 {score2}
<li>{username3} 的成績是 {score3}
<li>{username4} 的成績是 {score4}
</UL>
</BODY>
</HTML>
顯然,你采取了一個良好的命名方式,用1,2,3..來表示每一行數據,然后你在你的程序里循環給這些變量賦值,也是不難的,比如:(second.php)
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "first.html");
//連接數據庫,選擇數據庫略
省略.....
//查詢結果
$result = mysql_query("SELECT username,score FROM my_tbl");
//給文件中的模板變量賦值
$i=0;
while ($row = $idb->fetch_array($result))
{
$i++;
$tpl->set_var("username" . $i, $row["username"]);
$tpl->set_var("score" . $i, $row["score"]);
}
//完成替換
$tpl->parse("mains", "main");
//輸出
$tpl->pparse("mains", "main");
?>
這樣你也能得到正確結果.在特殊情況下你或許需要這樣做.但Template提供了一個更方便的"大的模板變量",那就是塊.我之所以稱之為"大的模板變量",是因為它也可以視為可以包含其他模板變量的變量.形式如
<UL>
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
</UL>
即用<!-- BEGIN 塊名稱 -->和<!-- END 塊名稱 -->定義了一個名為list的塊,(注意:我在這里為了方便理解,只稱之為塊名稱).這個塊里面又包含一些HTML代碼(<li>等等)以及模板變量({username},{score}).
在講述如何用塊輸出列表之前,我們先談一下塊的定義格式.
首先<!-- BEGIN list -->和<!-- END list --> 都要各自為一行,亦即下面的塊的定義是錯誤的
1,
同行的 <!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
2,
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list --> 同行的
<!--和-->都是固定的,也就是說只能是兩個中劃線("-"),且它們與BEGIN list之間都至少有一個空(空格或tab),看下面的例子
<!--BEGIN list -->
<!-- BEGIN list-->
它們都是錯誤的塊的定義方法,因為第一個<!--與BEGIN之間至少應該有一個空,第二個-->與list之間至少有一個空.
BEGIN/END和list之間也應該有一個空格,注意是有且僅有一個空格,不能多也不能少.
塊的名稱建議你只使用字符,數字,下劃線以及它們的組合.
BEGIN和END兩個詞語都應該是大寫的。
好了,下面開始探討如何是這個塊變成一個列表.我們可以這樣
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "second.html");
//加載塊list
$tpl->set_block("main", "list", "lists");
//連接數據庫,選擇數據庫略
省略.....
//查詢結果
$result = mysql_query("SELECT username,score FROM my_tbl");
//給文件中的模板變量賦值
while ($row = $idb->fetch_array($result))
{
$tpl->set_var("username", $row["username"]);
$tpl->set_var("score", $row["score"]);
$tpl->parse("lists", "list", true);
}
//完成替換
$tpl->parse("mains", "main");
//輸出
$tpl->pparse("mains", "main");
?>
記住把你的數據庫連接寫在我省略的部分,就可以打印正確的結果,一如
下面是一個列表
張三 的成績是 82
李四 的成績是 90
王兒 的成績是 60
麻子 的成績是 77
可以看到在PHP代碼里有兩個東西
$tpl->set_block("main", "list", "lists"); //代碼1
$tpl->parse("lists", "list", true);
就不可思議的將整個塊循環輸出了.代碼1用來加載模板main中的塊list,并給其一個名字lists,list就是模板中的一個大變量,它的內容就是<li>{username} 的成績是 {score}即:
"list" = "<li>{username} 的成績是 {score}"
之所以用lists命名,是為了程序的可讀性,也就是說我很容易就知道XXXs是XXX塊的名稱.
使用set_block后,模板中的塊內容
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
就被lists代替了.于是我們的模板就變成了
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 我的第二個模板文件 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
{lists}
</UL>
</BODY>
</HTML>
塊變成了一個變量(lists)!下面只要將lists變量替換成我們想要的就行了.
代碼二所處的循環
while ($row = $idb->fetch_array($result))
{
$tpl->set_var("username", $row["username"]);
$tpl->set_var("score", $row["score"]);
$tpl->parse("lists", "list", true); //代碼2
}
每一次循環,兩個set_var分別給username,score賦值,然后"list"就變成了
"list" = "<li>具體的名字 的成績是 具體的分數"
代碼2就是將list分析后的內容賦給lists,這樣就完成了整個塊的分析.
parse第三個參數可以設置list中的值是直接存在lists里面,還是附加在原有值之后.我們這里設置為true,說明是附加在原有值之后,才得以每個list的值都會顯示出來.反之設為false的話,后面的值會覆蓋掉以前的值.最終的結果會是
下面是一個列表
麻子 的成績是 77
綜上所述,Template模板類的替換方式是:
1,用set_block將模板中的list塊(或者你命名的其他塊)替換成變量lists.
2,用set_var給list塊中的變量賦值
3,把賦值并執行替換后的list內容依次給lists
4,完成分析
2005-11-8 23:20SOLO
在PHP程序里,我們常常會把"公用代碼"或"公用部分"寫進一個文件里,前者象我們的系統配置文件,比如config.php,或者公共函數都寫入一個functions.php文件里;后者象一個站點都需要用到的頁面頭部,尾部.這樣做的好處是可以很方便的維護站點,而如果這個公用部分要有所改動,無需再去改每一個頁面,大大減少了我們的工作量.
以前你或許用require,include(require_once,include_once)引進一個公用的頁面頭部,確實方便而有效,現在我們用Template模板類也可以實現了,并且可以很方便的把一個頁面隨意插入另一個模板的任意地方.如果你想也把要插進的頁面做成含有變量的模板的話,那么你會發現模板類會把這個工作處理的很好.
在template目錄下新建三個文件third.html,header.html,footer.html.內容分為如下
third.html
<!-- 這是頁面頭部 -->
{header}
<BODY>
下面是一個列表
<UL>
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
</UL>
<!-- 這是頁面腳部 -->
{footer}
</BODY>
</HTML>
header.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> {title} </TITLE>
</HEAD>
footer.html
<P>author © iwind
你也看到了,我們前幾節的例子中都是用
$tpl->set_file("main", "模板文件名");
來加載模板文件的。只所以命名為"main",是因為我們想給它一個意義:主模板。這里的third.html就可以稱之為“主模板”,而欲嵌入主模板third.html的{header}變量所在位置的模板文件header.html,則可以稱為"子模板".同樣footer.html也是一個"子模板",我們想把它放到主模板里的{footer}位置.一個主模板內可以隨意嵌入不限內容,尺寸大小,格式等的任何多個子模板.
下面我們開始我們的PHP程序.
先是創建一個類的實例對象
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//讀進三個模板文件的內容,分別給變量"main", "my_header", "my_footer"
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//執行my_header,my_footer里的模板變量替換,并把最終結果分別賦給主模板中的header,footer
$tpl->parse("header", "my_header");
$tpl->parse("footer", "my_footer");
//然后完成主模板內變量的替換,并輸出主模板分析后的內容
$tpl->parse("mains", "main");
//輸出
$tpl->p("mains");
于是,我們便可以通過查看源文件確信header.html,footer.html兩個子模板文件的內容已經被加進主模板里了.
<!-- 這是頁面頭部 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<!-- BEGIN list -->
<li> 的成績是
<!-- END list -->
</UL>
<!-- 這是頁面腳部 -->
<P>author © iwind
</BODY>
</HTML>
你會發現,所有的變量都沒了,包括我們未賦值的{title},{username},{score}.這是因為我們在創建對象時,第二個參數未設置,而自動采用了"remove"
$tpl = new Template("template");
和
$tpl = new Template("template", "remove");
的效果是一樣的.
如果我們想給這些變量也賦值,那么方法和單個模板里變量的分析方法是一樣的.
//讀模板內容進變量
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//設置子模板header.html里的變量title的值
$tpl->set_var("title", "這個是網頁標題");
//以下分析主模板里的塊的內容
//設置塊
$tpl->set_block("main", "list", "lists");
$array = array("張三" => 82, "李四" => 90, "王二" => 60, "麻子" => 77);
foreach ($array as $username=>$score)
{
? ? $tpl->set_var("username", $username);
? ? $tpl->set_var("score", $score);
? ? $tpl->parse("lists", "list", true);
}
所有程序為
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//設置header.html里的變量title的值
$tpl->set_var("title", "這個是網頁標題");
//設置塊
$tpl->set_block("main", "list", "lists");
$array = array("張三" => 82, "李四" => 90, "王二" => 60, "麻子" => 77);
foreach ($array as $username=>$score)
{
$tpl->set_var("username", $username);
$tpl->set_var("score", $score);
$tpl->parse("lists", "list", true);
}
//執行my_header,my_footer里的模板變量替換,并把最終結果分別賦給主模板中的header,footer
$tpl->parse("header", "my_header");
$tpl->parse("footer", "my_footer");
//完成主模板內變量的替換
$tpl->parse("mains", "main");
//輸出
$tpl->p("mains");
?>
輸出的結果為
<!-- 這是頁面頭部 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 這個是網頁標題 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<li>張三 的成績是 82
<li>李四 的成績是 90
<li>王二 的成績是 60
<li>麻子 的成績是 77
</UL>
<!-- 這是頁面腳部 -->
<P>author © iwind
</BODY>
</HTML>
一切都是我們所期望的.
在這個程序里,我們用
$tpl->set_block("main", "list", "lists");
加載一個塊.其實它的第一個參數為該塊所在父變量,如果這個塊在header.html里,那么恐怕要這樣寫了
$tpl->set_block("my_header", "list", "lists");
但分析方法還是一樣的.
從以往和這節中的例子,我們可以看出來,定義一個模板變量{var}值的方法是用
$tpl->set_var("var_name", "var_value");
但把一個變量的值給另一個變量就需要用parse.
$tpl->parse("target_name", "from_name", true);
或者
$tpl->parse("target_name", "from_name", false);
使用parse就先執行from_name大變量的模板變量的替換,然后再把所得結果賦給target_name.
一個變量{varname}無論在模板的何處(塊里面,子模板里),定義的方法都是一樣的.
子模板里還可以嵌入新的子模板,稱之為"多重嵌套",分析的方法都是一樣的,只是一般用不到.塊也可以多重嵌套,而且非常有用,使得模板可以設計的可以很清晰,這就是我們下一節的內容了.
以前你或許用require,include(require_once,include_once)引進一個公用的頁面頭部,確實方便而有效,現在我們用Template模板類也可以實現了,并且可以很方便的把一個頁面隨意插入另一個模板的任意地方.如果你想也把要插進的頁面做成含有變量的模板的話,那么你會發現模板類會把這個工作處理的很好.
在template目錄下新建三個文件third.html,header.html,footer.html.內容分為如下
third.html
<!-- 這是頁面頭部 -->
{header}
<BODY>
下面是一個列表
<UL>
<!-- BEGIN list -->
<li>{username} 的成績是 {score}
<!-- END list -->
</UL>
<!-- 這是頁面腳部 -->
{footer}
</BODY>
</HTML>
header.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> {title} </TITLE>
</HEAD>
footer.html
<P>author © iwind
你也看到了,我們前幾節的例子中都是用
$tpl->set_file("main", "模板文件名");
來加載模板文件的。只所以命名為"main",是因為我們想給它一個意義:主模板。這里的third.html就可以稱之為“主模板”,而欲嵌入主模板third.html的{header}變量所在位置的模板文件header.html,則可以稱為"子模板".同樣footer.html也是一個"子模板",我們想把它放到主模板里的{footer}位置.一個主模板內可以隨意嵌入不限內容,尺寸大小,格式等的任何多個子模板.
下面我們開始我們的PHP程序.
先是創建一個類的實例對象
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//讀進三個模板文件的內容,分別給變量"main", "my_header", "my_footer"
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//執行my_header,my_footer里的模板變量替換,并把最終結果分別賦給主模板中的header,footer
$tpl->parse("header", "my_header");
$tpl->parse("footer", "my_footer");
//然后完成主模板內變量的替換,并輸出主模板分析后的內容
$tpl->parse("mains", "main");
//輸出
$tpl->p("mains");
于是,我們便可以通過查看源文件確信header.html,footer.html兩個子模板文件的內容已經被加進主模板里了.
<!-- 這是頁面頭部 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<!-- BEGIN list -->
<li> 的成績是
<!-- END list -->
</UL>
<!-- 這是頁面腳部 -->
<P>author © iwind
</BODY>
</HTML>
你會發現,所有的變量都沒了,包括我們未賦值的{title},{username},{score}.這是因為我們在創建對象時,第二個參數未設置,而自動采用了"remove"
$tpl = new Template("template");
和
$tpl = new Template("template", "remove");
的效果是一樣的.
如果我們想給這些變量也賦值,那么方法和單個模板里變量的分析方法是一樣的.
//讀模板內容進變量
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//設置子模板header.html里的變量title的值
$tpl->set_var("title", "這個是網頁標題");
//以下分析主模板里的塊的內容
//設置塊
$tpl->set_block("main", "list", "lists");
$array = array("張三" => 82, "李四" => 90, "王二" => 60, "麻子" => 77);
foreach ($array as $username=>$score)
{
? ? $tpl->set_var("username", $username);
? ? $tpl->set_var("score", $score);
? ? $tpl->parse("lists", "list", true);
}
所有程序為
<?php
//包含進模板類 template.inc
require "inc/template.inc";
//創建一個實例
$tpl = new Template("template");
//將整個文件讀進來
$tpl->set_file("main", "third.html");
$tpl->set_file("my_header", "header.html");
$tpl->set_file("my_footer", "footer.html");
//設置header.html里的變量title的值
$tpl->set_var("title", "這個是網頁標題");
//設置塊
$tpl->set_block("main", "list", "lists");
$array = array("張三" => 82, "李四" => 90, "王二" => 60, "麻子" => 77);
foreach ($array as $username=>$score)
{
$tpl->set_var("username", $username);
$tpl->set_var("score", $score);
$tpl->parse("lists", "list", true);
}
//執行my_header,my_footer里的模板變量替換,并把最終結果分別賦給主模板中的header,footer
$tpl->parse("header", "my_header");
$tpl->parse("footer", "my_footer");
//完成主模板內變量的替換
$tpl->parse("mains", "main");
//輸出
$tpl->p("mains");
?>
輸出的結果為
<!-- 這是頁面頭部 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 這個是網頁標題 </TITLE>
</HEAD>
<BODY>
下面是一個列表
<UL>
<li>張三 的成績是 82
<li>李四 的成績是 90
<li>王二 的成績是 60
<li>麻子 的成績是 77
</UL>
<!-- 這是頁面腳部 -->
<P>author © iwind
</BODY>
</HTML>
一切都是我們所期望的.
在這個程序里,我們用
$tpl->set_block("main", "list", "lists");
加載一個塊.其實它的第一個參數為該塊所在父變量,如果這個塊在header.html里,那么恐怕要這樣寫了
$tpl->set_block("my_header", "list", "lists");
但分析方法還是一樣的.
從以往和這節中的例子,我們可以看出來,定義一個模板變量{var}值的方法是用
$tpl->set_var("var_name", "var_value");
但把一個變量的值給另一個變量就需要用parse.
$tpl->parse("target_name", "from_name", true);
或者
$tpl->parse("target_name", "from_name", false);
使用parse就先執行from_name大變量的模板變量的替換,然后再把所得結果賦給target_name.
一個變量{varname}無論在模板的何處(塊里面,子模板里),定義的方法都是一樣的.
子模板里還可以嵌入新的子模板,稱之為"多重嵌套",分析的方法都是一樣的,只是一般用不到.塊也可以多重嵌套,而且非常有用,使得模板可以設計的可以很清晰,這就是我們下一節的內容了.