小木学编程 之 PHPLib模板 作者:limodou
小木这几天看着站点的内容在一点一点地增加,心中充满着喜悦,但同时也有一些忧虑。维护是每个程序员一定会面临的问题,如何更有效的组织代码呢。在小木的建站初期,没有太仔细想过这个问题。但是现在..想一想,该如何作呢。很自然地,小木想起了模板。还有,前阵子翻译过关于PHP 中实现模板的文章。好了,就是它了。唉,也挺可笑的,自已翻译过的文章却没怎么试过(现在试也不晚嘛!)。
小木启动Apache,打开浏览器,找到了那篇文章《模板,PHPLIB处理方式》。文章中说要使用PHPLib库的template.inc文件就可以了。正好小木的站点上有PhpLib 7.2版软件。打开,查找,OK,找到了。于是小木将它解压到一个测试目录下。文章上说,PhpLib中的模板处理是使用了PHP 的对象编程,比另一个模板 FastTemplate要快,因为它使用的是preg函数集。但是,小木想到自已的主页空间好象不支持preg函数,这怎么办呢?先不管它了,先试一试再说吧。PHP4.0支持preg那就先用4.0吧。
为了方便管理,小木先建了一个子目录,名字为template,然后在下面建立了一个同文章上一样的模板。再将文章上的例子拷贝下来,只是把new Template("/home/mydir/mytemplates/"); 中的绝对路径改成了相对路径"template"。可是发现出问题了。屏幕显示: "Template Error: filename: file template/template/MyTemplate.ihtml does not exist." 怎么回事,模板文件名前面多了一个template。试了几遍均是如此。难道PhpLib中还有错误?没办法,小木只好一显身手了。打开template.inc看一看吧。仔细查看,加上测试,终于发现了,问题出现在filename()函数 中。
-------------------------------------------------------------------------------- function filename($filename) { if (substr($filename, 0, 1) != "/") { $filename = $this->root."/".$filename; }
if (!file_exists($filename)) $this-$gt;halt("filename: file $filename does not exist.");
return $filename; } -------------------------------------------------------------------------------- 问题就出现在对$filename的判断,当文件为相对目录时,文件名就使用根目录加上"/"和$filename ,这样就将文件名转化为相对于模板文件的文件名了。可是这段代码应该是正确的呀。再看一看,原来是调用set_file()时已经执行了filename函数,而在后面loadfile()时又执行了一遍,而正好这里用的是相对目录,所以会有上面的错。好了,由于在执行setfile()时已经执行过了,那么就把loadfile()的去掉吧。改完一试,一些ok。
接着,小木又拿自已的主页文件进行试验,结果又发现了一个问题。不过,别担心,不是PhpLib的问题,而是小木的问题。原来模板类会将所有的以"{"和"}"包括的内容当作模板变量处理,缺省时模板类会将所有未定义(即未使用set_var() 进行赋值的)的变量删除。而小木的主页中有样式定义,正好用的就是"{"和"}"包 括起来的,结果处理完后模板类将这些内容给删除了,造成结果不正确。那么怎么改呢?很简单在生成类时使用: $t = new Template("template", "keep"); "keey"表示保留不认识的"{"和"}"所包括的内容。这样就完全正确了。 可是小木的主页空间不支持preg函数集,要改造一下才可以用。小木仔细试验了一下,并且把一些认为用不上的函数删除(主要原因一是用不上,另外就是改起来不容易)。主要就是使用ereg_replace()函数来替换preg_replace()函数,同时将preg_replace()中使用的模式改成与ereg_replace()相兼容的格式,最后终于改成了。调用方式不变,但是可以在php3下使用。改动后的文件在下面。测试用例仍可使用文章上的例子。
--------------------------------------------------------------------------------
<?php /* * PHP3 Session 管理 * * (C) Copyright 1999 NetUSE GmbH * Kristian Koehntopp * * $Id: 1387,v 1.7 2000/10/23 14:50:21 sympa Exp sympa $ * * 译者:limodou chatme@263.net * */
class Template { var $classname = "Template";
/* 如果设置了,则输出参数 */ var $debug = false;
/* $file[handle] = "filename"; */ var $file = array();
/* 相对的文件名是相对此目录 */ var $root = "";
/* $varkeys[key] = "key"; $varvals[key] = "value"; */ var $varkeys = array(); var $varvals = array();
/* "remove" => 删除未定义的变量 * "comment" => 将未定义的变量变成注释 * "keep" => 保留未定义的变量 */ var $unknowns = "remove"; /* "yes" => 退出 * "report" => 报告错误,继续运行 * "no" => 忽略错误 */ var $halt_on_error = "yes"; /* 上一次的错误保存在这里 */ var $last_error = "";
/***************************************************************************/ /* public: 构造函数 * root: 模板目录 * unknowns: 如何处理未知的变量(译者:变量定义为{name}) */ function Template($root = ".", $unknowns = "remove") { $this->set_root($root); $this->set_unknowns($unknowns); }
/* public: setroot(pathname $root) * comment: 设置模板起始目录 * root: 新的模板目录 */ function set_root($root) { if (!is_dir($root)) { $this->halt("set_root: $root 不是一个目录。"); return false; } $this->root = $root; return true; }
/* public: set_unknowns(enum $unknowns) * comment: 设置对未知变量的处理 * unknowns: "remove", "comment", "keep" * */ function set_unknowns($unknowns = "keep") { $this->unknowns = $unknowns; }
/* public: set_file(array $filelist) * comment: 设置多个模板文件 * filelist: (句柄,文件名)数组 * * public: set_file(string $handle, string $filename) * comment: 设置一个模板文件 * handle: 文件的句柄 * filename: 模板文件名 */ function set_file($handle, $filename = "") { if (!is_array($handle)) { if ($filename == "") { $this->halt("set_file: 句柄 $handle 为空。"); return false; } $this->file[$handle] = $this->filename($filename); } else { reset($handle); while(list($h, $f) = each($handle)) { $this->file[$h] = $this->filename($f); } } }
/* public: set_var(array $values) * values: (变量名,值)数组 * * public: set_var(string $varname, string $value) * varname: 将被定义的变量名 * value: 变量的值 */ function set_var($varname, $value = "") { if (!is_array($varname)) { if (!empty($varname)) if ($this->debug) print "set_var: 设置 *$varname* 为 *$value*br "; // $this->varkeys[$varname] = "/".$this->varname($varname)."/"; $this->varkeys[$varname] = "{$varname}"; $this->varvals[$varname] = $value; } else { reset($varname); while(list($k, $v) = each($varname)) { if (!empty($k)) if ($this->debug) print "set_var: 设置 *$k* 为 *$v*br "; // $this->varkeys[$k] = "/".$this->varname($k)."/"; $this->varkeys[$k] = "{$k}"; $this->varvals[$k] = $v; } } }
/* public: subst(string $handle) * handle: 模板句柄,其中的变量将被替换 */ function subst($handle) { if (!$this->loadfile($handle)) { $this->halt("subst: 不能装入 $handle."); return false; }
$str = $this->get_var($handle); // $str = preg_replace($this->varkeys, $this->varvals, $str); $str=$this->replaceall($this->varkeys, $this->varvals, $str); return $str; } /* public: psubst(string $handle) * handle: 模板句柄,其中的变量将被替换 */ function psubst($handle) { print $this->subst($handle); return false; }
/* public: parse(string $target, string $handle, boolean append) * public: parse(string $target, array $handle, boolean append) * target: 将要生成的模板句柄 * handle: 进行替换的模板句柄 * append: 是否在target句柄后进行追加 */ function parse($target, $handle, $append = false) { if (!is_array($handle)) { $str = $this->subst($handle); if ($append) { $this->set_var($target, $this->get_var($target) . $str); } else { $this->set_var($target, $str); } } else { reset($handle); while(list($i, $h) = each($handle)) { $str = $this->subst($h); $this->set_var($target, $str); } }
return $str; } function pparse($target, $handle, $append = false) { print $this->parse($target, $handle, $append); return false; } /* public: get_vars() */ function get_vars() { reset($this->varkeys); while(list($k, $v) = each($this->varkeys)) { $result[$k] = $this->varvals[$k]; } return $result; } /* public: get_var(string varname) * varname: 变量名 * * public: get_var(array varname) * varname: 变量名数组 */ function get_var($varname) { if (!is_array($varname)) { return $this->varvals[$varname]; } else { reset($varname); while(list($k, $v) = each($varname)) { $result[$k] = $this->varvals[$k]; } return $result; } } /* public: finish(string $str) * str: string to finish. */ function finish($str) { switch ($this->unknowns) { case "keep": break; case "remove": //modi $str = preg_replace("/{[^}]+}/", "", $str); $str = ereg_replace("{[^}]+}", "", $str); break;
case "comment": //modi $str = preg_replace("/{([^}]+)}/", "<!-- Template $handle: Variable undefined -->", $str); $str = ereg_replace("{([^}]+)}", "<!-- Template $handle: Variable undefined -->", $str); break; } return $str; }
/* public: p(string $varname) * varname: name of variable to print. */ function p($varname) { print $this->finish($this->get_var($varname)); }
function get($varname) { return $this->finish($this->get_var($varname)); } /***************************************************************************/ /* private: filename($filename) * filename: name to be completed. */ function filename($filename) { if (substr($filename, 0, 1) != "/") { $filename = $this->root."/".$filename; }
if (!file_exists($filename)) $this->halt("filename: 文件 $filename 不存在。");
return $filename; } /* private: varname($varname) * varname: 被保护的可替换变量名字 */ function varname($varname) { // return preg_quote("{".$varname."}"); return $this->squote("{$varname}"); }
//增加
function squote($str) { for($i=0; $i<strlen($str); $i++) { switch($str[$i]) { case '|': case ':': case '.': case '[': case ']': case '*': case '?': case '+': case '{': case '}': case '/': case '\': $s .= "\".$str[$i]; break; default: $s .= $str[$i]; } } return $s; }
/* private: loadfile(string $handle) * handle: 装入由handle指定的文件, 在它还未装入时 */ function loadfile($handle) { if ($this->varkeys[$handle] and !empty($this->varvals[$handle])) return true;
if (!isset($this->file[$handle])) { $this->halt("loadfile: $handle 不是一个有效有句柄。"); return false; } // $filename = $this->filename($this->file[$handle]); $filename = $this->file[$handle];
$str = implode("", @file($filename)); if (empty($str)) { $this->halt("loadfile: 装入 $handle 时, $filename 不存在或为空。"); return false; }
$this->set_var($handle, $str); return true; }
/***************************************************************************/ /* public: halt(string $msg) * msg: 用于显示的错误信息 */ function halt($msg) { $this->last_error = $msg;
if ($this->halt_on_error != "no") $this->haltmsg($msg);
if ($this->halt_on_error == "yes") die("bHalted./b");
return false; } /* public, override: haltmsg($msg) * msg: 用于显示的错误信息 */ function haltmsg($msg) { printf("b模板错误:/b %sbr ", $msg); }
function replaceall($pattern, $replacement, $str) { if (!is_array($pattern)) { if (!empty($pattern)) { if ($this->debug) print "replaceall: 设置 *$pattern* 为 *$replacement*br "; $str=ereg_replace($pattern, $replacement, $str); if ($this->debug) print "replaceall, str=: *$str*br "; } } else { reset($pattern); while(list($k, $v) = each($pattern)) { if (!empty($k)) { if ($this->debug) { $a=$this->varkeys[$k]; $b=$this->varvals[$k]; print "replaceall: 设置 *$a* 为 *$b*br "; } $str=ereg_replace($this->varkeys[$k], $this->varvals[$k], $str); if ($this->debug) print "replaceall, str=: *$str*br "; } } } return $str; }
}//end of class
?>
|