<?php /** * {loop $array $key $value}..........{/loop} 循环 * {loop $array $value}..........{/loop} 循环 * {if condition}...{elseif condition}..{else}..{/if} if条件语句 * {$val} 输出变量值 * {eval echo "ok";} 运行PHP代码 * {template file} 包含另外一个模版 * 对象方法: * setTemplateDir($dir) * setReal($real) * setExtName($ext) * setTmpDir($dir) * setU(&$dispatcher) * assign($name, $value=null) * getVal($name) * saveHtml($tFile, $html) * display($tFile) */ class Template { private $tDir; //模版文件目录 private $tTmpDir; //编译好后的文件目录 private $tVal; //模版变量 private $tFile; //模版文件 private $tExtName = '.html'; //模板文件的扩展名 private $tContent; //模版内容 private $uDispatcher; //URL调度器 private $real = false; //实时编译 public function __construct() { $this->tVal = array(); } /** * 设置模版文件目录 * @param string $dir */ public function setTemplateDir($dir) { $this->tDir = $dir; } /** * 是否实时编译 * @param bool $real */ public function setReal($real) { $this->real = (bool) $real; } /** * 设置模板文件的扩展名 * @param string $ext 扩展名 */ public function setExtName($ext) { $this->tExtName = $ext; } /** * 临时文件目录 * @param string $dir */ public function setTmpDir($dir) { if (!file_exists($dir)) { if (!mkdir($dir, 0, true)) die("tmp dir $dir can't to mkdir"); } $this->tTmpDir = realpath($dir); } /** * URL调度器 * @param Dispatcher $dispatcher */ public function setU(&$dispatcher) { if (is_object($dispatcher) && method_exists($dispatcher, 'U')) { $this->uDispatcher = $dispatcher; } } /** * 注册用户自己的函数 * 当$function是string时则是方函数,如果是键值对数组时则键是类名,值是类中的静态方法 * @param mix $function 函数 */ public function registerFunction($function) { if (is_array($function)) { foreach ($function as $key => $value) { $this->userFunctions['classes'][$key] = $value; } } else { $this->userFunctions['functions'][] = $function; } } /** * 变量赋值 * 如果$name是一个键值对的数组,则直接使用对$name数组进行赋值 * @param mixed $name 变量名 * @param mixed $value 值 */ public function assign($name, $value=null) { if (is_array($name)) { foreach ($name as $key => $val) { $this->tVal[$key] = $val; } } else { $this->tVal[$name] = $value; } } /** * 取得模版的变量 * @param string $name */ public function getVal($name) { if (isset($this->tVal[$name])) { return $this->tVal[$name]; }else return false; } /** * 将运行好后的内容,保存到一个html文件中 * @param string $tFile * @param string $html */ public function saveHtml($tFile, $html) { ob_start(); $this->display($tFile); $buffer = ob_get_contents(); ob_end_clean(); file_put_contents($html, $buffer); } /** * 运行并显示模版内容 * @param string $tfile */ public function display($tFile) { $this->tFile = $this->parseTemplatePath($tFile); if (!file_exists($this->getTmpFile()) || $this->real) { $this->parse(); } extract($this->tVal, EXTR_OVERWRITE); include $this->getTmpFile(); } /** * 编译好后的文件 * @return string $filepath */ private function getTmpFile() { $basename = basename($this->tFile); $pos = strrpos($basename, '.'); $tmp = 'tpl_' . substr($basename, 0, $pos) . '.php'; return $this->tTmpDir . '/' . $tmp; } private function parse() { $this->tContent = file_get_contents($this->tFile); $this->parseInclude(); $this->parseSection(); $this->parseVal(); $this->parseEval(); if (!$this->real) { //如果是在非调试环境下,则替换一些没用的内容 $search = array("/\r?\n/", "/\s{2,}/"); $repace = array('', ''); $this->tContent = preg_replace($search, $repace, $this->tContent); } file_put_contents($this->getTmpFile(), $this->tContent); } /** * 解析模板中的子模板 */ private function parseInclude() { for ($i = 0; $i < 6; $i++) { $this->tContent = preg_replace("/\{template\s+([a-zA-z0-9\._]+)\}/ies", "\$this->subtemplate('$1')", $this->tContent); } } /** * 获取只模版 * @param string $file */ private function subtemplate($file) { return file_get_contents($this->parseTemplatePath($file)); } /** * 解析模版路径 * @param string $file * @return string $filepath */ private function parseTemplatePath($tFile) { $tFile.=$this->tExtName; $tFile = $this->tDir ? $this->tDir . '/' . $tFile : $tFile; if (!file_exists($tFile)) { die("No template file $tFile"); } else { $tFile = realpath($tFile); } return $tFile; } /** * 解析变量 */ private function parseVal() { $this->tContent = preg_replace("/\{(\\$\S+?)\}/is", "<?php echo \\1 ;?>", $this->tContent); } /** * 解析段落 */ private function parseSection() { //逻辑 $this->tContent = preg_replace("/\{elseif\s+(.+?)\}/ies", "\$this->stripvtags('<?php } elseif(\\1) { ?>','')", $this->tContent); $this->tContent = preg_replace("/\{else\}/is", "<?php } else { ?>", $this->tContent); $this->tContent = preg_replace("/\{U\((.+?)\)\}/ies", "\$this->parseUrl('$1')", $this->tContent); //循环 for ($i = 0; $i < 6; $i++) { $this->tContent = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}(.+?)\{\/loop\}/ies", "\$this->stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2) { ?>','\\3<?php } } ?>')", $this->tContent); $this->tContent = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}(.+?)\{\/loop\}/ies", "\$this->stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>','\\4<?php } } ?>')", $this->tContent); $this->tContent = preg_replace("/\{if\s+(.+?)\}(.+?)\{\/if\}/ies", "\$this->stripvtags('<?php if(\\1) { ?>','\\2<?php } ?>')", $this->tContent); } } private function stripvtags($expr, $statement='') { $expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr)); $statement = str_replace("\\\"", "\"", $statement); return $expr . $statement; } /** * 解析PHP语句 */ private function parseEval() { $this->tContent = preg_replace("/\{eval\s+(.+?)\}/is", "<?php $1 ?>", $this->tContent); } /** * 解析URL */ private function parseUrl($url) { if (is_object($this->uDispatcher)) { return $this->uDispatcher->U($url); } else { return $url; } } } ?>