MVC是现在很流行的程式架构,因为按照功能分开后,更容易扩充和维护,其中的View会写成接收外来的变数来呈现资料,不处理资料取得和商业逻辑,因此便有了各种的样板引擎来让这件事情更容易达成
今天要介绍的是一款PHP的样板引擎,它没有名称,也不有名,来自这一篇文章Template Engine,简体翻译,但笔者却非常推崇,原因无他,就是非常的简单易用,通常样板引擎需要另外安装,有着专用的语法,用来呈现、过滤资料,并且可以用好几个小样板,组合出画面,每一个小样板都可以重複使用,避免重複开发
而这款却不需安装,仅用一个class便实现样板引擎的功能,甚至还有快取功能,不需要学新的语法,因为直接使用php语言,这有好有坏,设计师需要学习php语言,但虽然如此,用到的php其实不会太複杂,跟学习smarty相比,应该差不多难度,另外一个疑虑是,如果你的网站允许使用者上传样板修改版面,使用php语言变成自由度太大了,无法防止被上传包含恶意程式码的样板,不过这篇文章是在2003年写的,如今都是使用修改css的方式让使用者修改版面,所以这个疑虑也不存在了
事不宜迟,来看看这个class到底长的怎样
class Template { var $vars; /// Holds all the template variables /** * Constructor * * @param $file string the file name you want to load */ function Template($file = null) { $this->file = $file; } /** * Set a template variable. */ function set($name, $value) { $this->vars[$name] = is_object($value) ? $value->fetch() : $value; } /** * Open, parse, and return the template file. * * @param $file string the template file name */ function fetch($file = null) { if(!$file) $file = $this->file; extract($this->vars); // Extract the vars to local namespace ob_start(); // Start output buffering include($file); // Include the file $contents = ob_get_contents(); // Get the contents of the buffer ob_end_clean(); // End buffering and discard return $contents; // Return the contents }}/** * An extension to Template that provides automatic caching of * template contents. */class CachedTemplate extends Template { var $cache_id; var $expire; var $cached; /** * Constructor. * * @param $cache_id string unique cache identifier * @param $expire int number of seconds the cache will live */ function CachedTemplate($cache_id = null, $expire = 900) { $this->Template(); $this->cache_id = $cache_id ? 'cache/' . md5($cache_id) : $cache_id; $this->expire = $expire; } /** * Test to see whether the currently loaded cache_id has a valid * corrosponding cache file. */ function is_cached() { if($this->cached) return true; // Passed a cache_id? if(!$this->cache_id) return false; // Cache file exists? if(!file_exists($this->cache_id)) return false; // Can get the time of the file? if(!($mtime = filemtime($this->cache_id))) return false; // Cache expired? if(($mtime + $this->expire) < time()) { @unlink($this->cache_id); return false; } else { /** * Cache the results of this is_cached() call. Why? So * we don't have to double the overhead for each template. * If we didn't cache, it would be hitting the file system * twice as much (file_exists() & filemtime() [twice each]). */ $this->cached = true; return true; } } /** * This function returns a cached copy of a template (if it exists), * otherwise, it parses it as normal and caches the content. * * @param $file string the template file */ function fetch_cache($file) { if($this->is_cached()) { $fp = @fopen($this->cache_id, 'r'); $contents = fread($fp, filesize($this->cache_id)); fclose($fp); return $contents; } else { $contents = $this->fetch($file); // Write the cache if($fp = @fopen($this->cache_id, 'w')) { fwrite($fp, $contents); fclose($fp); } else { die('Unable to write cache.'); } return $contents; } }}
可以看到有2个class,第1个实现样板功能,第2个继承第1个进一步实现快取功能,原理相当简单,看fetch方法便知道,利用extract传进来的阵列变成键值为名称的变数,然后使用缓冲区,将样板档引用执行,便会自动套用变数把html产生,将结果存在变数内,然后再输出缓冲并回传,就可以取得套好的html字串了,真的非常有巧思,样板档会长这样子
<html> <head> <title><?=$title;?></title> <link href="style.css" rel="stylesheet" type="text/css" /> </head> <body> <h1><?=$title;?></h1> <?=$content;?> </body></html>
<table cellpadding="3" border="0" cellspacing="1" bgcolor="#CCCCCC"> <tr> <td bgcolor="#F0F0F0">Id</td> <td bgcolor="#F0F0F0">Name</td> <td bgcolor="#F0F0F0">Email</td> <td bgcolor="#F0F0F0">Banned</td> </tr><?php foreach($users as $user): ?> <tr> <td bgcolor="#FFFFFF" align="center"><?=$user['id'];?></td> <td bgcolor="#FFFFFF"><?=$user['name'];?></td> <td bgcolor="#FFFFFF"><a href="mailto:<?=$user['email'];?>"><?=$user['email'];?></a></td> <td bgcolor="#FFFFFF" align="center"><?=($user['banned'] ? 'X' : ' ');?></td> </tr><?php endforeach; ?></table>
绝大部分是html,少部分是php输出,之后使用方法如下:
$tpl = new Template('index.tpl'); // this is the outer template$tpl->set('title', 'User List');$body = new Template('body.tpl'); // This is the inner template/* * The get_list() method of the User class simply runs a query on * a database - nothing fancy or complex going on here. */$body->set('user_list', $user->get_list());$tpl->set('content', $body);echo $tpl->fetch('index.tpl');
只需要读取样板档,然后填入样板档内定义的变数,甚至可以填入另一个样板档,达到重複使用的效果,是不是非常简单易用呢,最后说明一下快取的部分,每次存取的时候,判断是否有相同快取档存在,快取档档名会使用传入的字串编成md5,作者建议使用网址带get的参数,这样参数不同时,快取得档案也不同,然后可以设置快取过期时间,会自动检查快取档到当前时间是否已超过过期时间,若还没则直接读取快取档内容,超过则重新建立,算是方便易用的快取方式喔~