最近有点闲,又好长时间没写什么代码了,就随便想点什么东西来写一写。按着自己的想法写了个简易版的模板引擎原型,估计smarty之类的模板引擎也是差不多这样实现。模板引擎的好处是实现业务逻辑和页面的分离,比起各种MVC的框架,模板引擎这东西实用多了。所以研究一下它的实现原理,好处还是有不少的。废话少说,直接上代码。
模板引擎代码:
<?php
class Template
{
private $tpl_file_name;
private $internal_vars = array();
private $compile_contents;
private $html_contents;
public function __construct($tpl_file_name) {
$this->tpl_file_name = $tpl_file_name;
$handle = fopen($tpl_file_name, 'r');
while (!feof($handle)) {
$this->compile_contents .= fread($handle, 8192);
}
fclose($handle);
}
private function compile() {
$tmp_content = $this->formatInternalVars();
$tmp_content .= preg_replace('/\{\$(.*?)\}/',
"<?php echo \$global_arr['\\1']; ?>", $this->compile_contents);
$handle = fopen($this->tpl_file_name.'.php', 'w');
fwrite($handle, $tmp_content);
fclose($handle);
}
public function getHtmlContents() {
$this->compile();
ob_start();
require_once $this->tpl_file_name.'.php';
$this->html_contents = ob_get_contents();
ob_end_clean();
return $this->html_contents;
}
public function assign($name, $value) {
$this->internal_vars[$name] = $value;
}
private function formatInternalVars() {
$str = '<?php ';
$str .= 'header("Content-type: text/html; charset=utf-8");';
$str .= '$global_arr = array(';
$len = strlen($str);
foreach($this->internal_vars as $k => $v) {
if(strlen($str) != $len) {
$str .= ',';
}
$str .= "'$k'=>'$v'";
}
$str .= ');';
$str .= ' ?>';
return $str;
}
private function outputHtml() {
$handle = fopen($this->tpl_file_name.'.html', 'w');
fwrite($handle, $this->getHtmlContents());
fclose($handle);
}
public function display() {
$this->outputHtml();
echo $this->html_contents;
}
}
?>
模板代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<TITLE>{$title}</TITLE>
</HEAD>
<BODY>
{$body}
</BODY>
</HTML>
测试代码:
<?php
require 'Template.class.php';
$tpl = new Template('index.htm');
$tpl->assign('title', '我的模板引擎 - 听我的');
$tpl->assign('body', '中华大地,天下畅达,哈哈哈哈');
$tpl->display();
?>