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