转载:http://bbs.cnaust.com/archiver/?tid-4849.html

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以上.




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
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,完成分析

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 &copy; 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 &copy; 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 &copy; 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}无论在模板的何处(块里面,子模板里),定义的方法都是一样的.

子模板里还可以嵌入新的子模板,称之为"多重嵌套",分析的方法都是一样的,只是一般用不到.块也可以多重嵌套,而且非常有用,使得模板可以设计的可以很清晰,这就是我们下一节的内容了.
posted on 2006-08-10 12:17 jackstudio 阅读(587) 评论(0)  编辑  收藏 所属分类: php

只有注册用户登录后才能发表评论。


网站导航: