仿制smarty模板
2016-06-03 04:49
316 查看
仿制smarty的模板技术,写了一个自己的mySmarty,供大家参考,和玩转
这是一个仿制的smarty模板
可以给简单变量以及数组变量赋值
在模板中可以使用foreach循环以及if条件语句
demo.php
MySmarty/MySmarty.class.php
MySmarty/MySmartyCompile.class.php
templates/demo.tpl.html
这是一个仿制的smarty模板
可以给简单变量以及数组变量赋值
在模板中可以使用foreach循环以及if条件语句
demo.php
<?php require_once 'MySmarty/MySmarty.class.php'; require_once 'MySmarty/MySmartyCompile.class.php'; $minismarty = new MySmarty(); //缓存开关 $minismarty->caching = true; //定义变量 $webname = 'my Smarty test'; $message = array( 'title'=>'this is title', 'content', 'userMessage'=>array( array('name'=>'this is johnny','gender'=>1), array('name'=>'this is lei','gender'=>1), array('name'=>'this is nicolas','gender'=>1), array('name'=>'this is ada','gender'=>0), ), 'bookMessage'=> array( array('name'=>'this is johnny','id'=>1), array('name'=>'this is lei','id'=>2), array('name'=>'this is nicolas','id'=>3), array('name'=>'this is ada','id'=>4), ), array( 'friendMessage'=>array( array('name','id'), array('johnny',1), array('nicolas',2), array('leiyuqing2222222222222',3), ), ), ); $message1 = array( 'userMessage'=>array( array('name'=>'this is johnny','gender'=>1), array('name'=>'this is lei','gender'=>1), array('name'=>'this is nicolas','gender'=>1), array('name'=>'this is ada','gender'=>0), ), 'bookMessage'=> array( array('name'=>'this is book1','id'=>1), array('name'=>'this is book2','id'=>2), array('name'=>'this is book3','id'=>3), array('name'=>'this is book4','id'=>4), ), ); $simpleArr = array('cc','dd','ee'); $dyadicArr = array( array('ff','gg','hh'), 'key'=>array('ii','jj','kk'), ); $keyArr = array( 'aa'=>'AA', 'bb'=>'BB', 'cc'=>'cc', ); $userMessage = array( array('name'=>'this is johnny','gender'=>1), array('name'=>'this is lei','gender'=>1), array('name'=>'this is nicolas','gender'=>1), array('name'=>'this is ada','gender'=>0), ); $gender = 0; $minismarty->assign('webname', $webname); $minismarty->assign('message', $message); $minismarty->assign('message1', $message1); $minismarty->assign('userMessage', $userMessage); $minismarty->assign('simpleArr', $simpleArr); $minismarty->assign('dyadicArr', $dyadicArr); $minismarty->assign('keyArr', $keyArr); $minismarty->assign('gender', $gender); //启动编译模板文件 $minismarty->display('demo.tpl.html');
MySmarty/MySmarty.class.php
<?php class MySmarty { //模板文件 public $template_dir = 'templates'; //编译文件 public $compile_dir = 'templates_c'; //缓存文件 public $cache_dir = 'cache'; //模板变量 public $_tpl_var = array(); //是否开启缓存 public $caching = false; public $left_delimiter = "{"; public $right_delimiter = '}'; public function __construct() { $this->checkDir(); } //检查目录是否建好 private function checkDir() { if (!is_dir($this->template_dir)) { exit('模板文件目录templates不存在!请手动创建'); } if (!is_dir($this->compile_dir)) { exit('编译文件目录templates_c不存在!请手工创建!'); } if (!is_dir($this->cache_dir)) { exit('缓存文件目录'.$this->cache_dir.'不存在!请手工创建!'); } } //模板变量注入方法 public function assign($tpl_var, $var = null) { if (isset($tpl_var) && !empty($tpl_var)) { $this->_tpl_var[$tpl_var] = $var; } else { exit('模板变量名没有设置好'); } } //文件编译 public function display($file) { //模板文件 $tpl_file = $this->template_dir.'/'.$file; if (!file_exists($tpl_file)) { exit('ERROR:模板文件不存在!'); } //编译文件 $parse_file = $this->compile_dir.'/'.md5($file).$file.'.php'; //只有当编译文件不存在或者是模板文件被修改过了 //才重新编译文件 if (!file_exists($parse_file) || filemtime($parse_file) < filemtime($tpl_file)) { $compile = new MySmartyCompile($tpl_file); $compile->parse($parse_file); } // 如果缓存没有开启 if (!$this->caching) { include $parse_file; return ; } //开启了缓存才加载缓存文件,否则直接加载编译文件 //缓存文件 $cache_file = $this->cache_dir.'/'.md5($file).$file; //只有当缓存文件不存在,或者编译文件已被修改过 //重新生成缓存文件 if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) { ob_start(); //引入缓存文件 include $parse_file; //缓存内容 $content = ob_get_contents(); ob_end_clean(); //生成缓存文件 if (!file_put_contents($cache_file, $content)) { exit('缓存文件生成出错!'); } } //载入缓存文件 include $cache_file; } }
MySmarty/MySmartyCompile.class.php
<?php class MySmartyCompile { //模板内容 private $content = ''; //构造函数 public function __construct($tpl_file) { $this->content = file_get_contents($tpl_file); } //解析普通变量,如把{$name}解析成$this->_tpl_var['name'] public function replaceSimpleVar() { /** * 这个正则表达式是指匹配简单变量 * 不匹配$xxx.或者$xxx[或者$xxx]既不匹配对象和数组 * 也不匹配关键字,比如{foreach}等等 */ $pattern = '/\{\$(\w+(?!\.|\[|\]))\}/'; if (preg_match($pattern, $this->content)) { $this->content = preg_replace($pattern, '<?php echo \$this->_tpl_var["$1"]?>', $this->content); } } public function replaceVar() { /** * $webname.name.cc.dd * $webname.name.cc[1].dd * $author[1][12].name[0] * $title[1] * $title.dd * $title.dd[1] */ // \$(\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)? // \$((\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)?) // $pattern = '/\{\$((\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)?)\}/'; $pattern = '/\{\$([^\{\}]+)\}/'; $matches = array(); preg_match_all($pattern, $this->content,$matches); for($i = 0; $i < count($matches[1]); $i++) { $str = $this->parseVar($matches[1][$i]); $str = "<?php echo ".$str."?>"; $this->content = str_replace($matches[0][$i], $str, $this->content); } } /** * 传进来的是一个变量的字串,比如$name,$name[1],$message.name[2]之内的 * 把这个字符串转化成我们的$this->_tpl_var开头的变量 * 比如$name => $this->_tpl_var['name'] * $name[1] =>$this->_tpl_var['name'][1] * $message.name[2] => $this->_tpl_var['message']['name'][2] * 返回传化后的字符串 * @param type $arrStr * @return str */ public function parseVar($arrStr) { $str = '$this->_tpl_var'; $explodeFlag = '.'; $subStr = explode($explodeFlag, $arrStr); for ($i = 0; $i < count($subStr); $i++) { $pattern = '/(\w+)((\[\d+\])+)/'; if(!preg_match($pattern, $subStr[$i], $matches)) { $str .= "["."'".$subStr[$i]."'"."]"; continue; } $str .= "["."'".$matches[1]."'"."]".$matches[2]; } return $str; } /** * 这个函数的作用是替换模板文件中的foreach语句块,和if语句块 */ public function replaceSpecialWords() { /** * 这个正则表达式匹配{{XXX}}里面的东西,既if语句块和foreach语句块 * 这个xxx不能包含{{ * 如果这个语句块是if,那个就要以{/if}结尾,如果是foreach,那么就以{/foreach}结尾 */ $pattern = '/\{(\{(\w+)(?:(?!\{\{).|\n)+\{\/\2\})\}/'; $matches = array(); preg_match_all($pattern, $this->content, $matches); for($i = 0; $i < count($matches[1]);$i++) { $str = $this->parseSpecialWords($matches[1][$i]); $this->content = str_replace($matches[0][$i], $str, $this->content); } } public function parseSpecialWords($str) { /** * 匹配出{}或是{{}或是{}}里面的字符串 */ $pattern = '/\{([^\{\}]+)\}/'; preg_match_all($pattern, $str, $matches); /** * 匹配出第一行里面的变量,并且将他替换掉 */ $reg = '/\((\$([^\s]+))/'; preg_match($reg, $matches[0][0], $var); $tmp = $this->parseVar($var[2]); $matches[1][0] = str_replace($var[1], $tmp, $matches[1][0]); /** * flag用来记录这个foreach语句还是if语句块 * flag = fo or if */ $flag = substr($matches[1][0], 0,2); /** * replace 根据每一行情况不同,赋不同的php语句,替换掉伪代码 b454 */ $replace = ''; $count = count($matches[1]); for ($i = 0; $i < $count; $i++) { /** * 匹配循环里面需要输出的变量 */ $reg1 = '/^\$\w+$/'; if (preg_match($reg1, $matches[1][$i])) { /** * 找到需要输出的变量 */ $replace = "<?php echo ".$matches[1][$i]." ?>"; } else if($matches[1][$i] == $matches[1][$count-1] || substr($matches[1][$i],0,1) == '/'){ /** * 找到结束的地方,用}替换掉 */ $replace = "<?php } ?>"; } else if(substr($matches[1][$i],0,4) == 'else'){ /** * 如果是else开头,那么应该在else前面加上一个}然后再在语句后面加上一个{ */ $replace = "<?php }".$matches[1][$i]."{ ?>"; } else if($flag == 'if' && substr($matches[1][$i],0,2) == 'fo'){ /** * 这种情况是if语句块里面嵌套foreach语句,因为if的条件变量和foreach的循环变量一般不会相同所以要特殊考虑 * 既如果用一个flag来控制if怎么走,然后foreach里面的循环变量数组如果是message,那么我们得要找到message的值 */ //示例字符串foreach ($dyadicArr as $value) $reg = '/\((\$([^\s]+))/'; preg_match($reg, $matches[0][$i], $var); $tmp = $this->parseVar($var[2]); $matches[1][$i] = str_replace($var[1], $tmp, $matches[1][$i]); $flag = 'fo'; $replace = "<?php ".$matches[1][$i]."{ ?>"; } else { /** * 找到循环开始的地方,应该在语句后面加上一个{ */ $replace = "<?php ".$matches[1][$i]."{ ?>"; } $str = str_replace($matches[0][$i], $replace, $str); } return $str; } //模板编译 public function parse($parse_file) { ini_set('pcre.backtrack_limit', -1); // ini_set('pcre.recursion_limit', 99999); //解析foreach和if语句块 $this->replaceSpecialWords(); //解析变量 $this->replaceVar(); //编译完成后,生成编译文件 if (!file_put_contents($parse_file, $this->content)) { exit('编译文件生成出错!'); } } }
templates/demo.tpl.html
<html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p>**********这个是一个简单变量**************</p> {$webname} <p>**********这是一个数组里面的元素************</p> {$message[1].friendMessage[1][0]} <p>*************这里是一个If语句块***********</p> {{if($gender == 1)} <p>male</p> {else} <p>female</p> {/if}} <p>***************这里是一个简单的for循环**************</p> {{foreach ($dyadicArr as $value)} {foreach ($value as $v)} <p>{$v}</p> {/foreach} {/foreach}} <p>*************这是foreach循环里面嵌套一个If语句块********</p> {{foreach ($userMessage[1] as $k => $v)} {if($v == 1)} <p>{$k} => male</p> {else if($v == 0)} <p>{$k} => female</p> {else } <p>{$k} => {$v}</p> {/if} {/foreach}} <p>*******这里是3重foreach语句块嵌套********</p> {{foreach ($message1 as $key1 => $value1)} {$key1} => {foreach ($value1 as $key2 => $value2)} {foreach ($value2 as $key3 => $value3)} <p>{$key3}=>{$value3}</p> {/foreach} {/foreach} {/foreach}} </body> </html>
相关文章推荐
- 一个关于if else容易迷惑的问题
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- JSP/PHP基于Ajax的分页功能实现
- msql 正则表达式
- 正则表达式
- 关于PHP通过PDO用中文条件查询MySQL的问题。
- 什么是设计模式
- PHP数据库长连接mysql_pconnect的细节
- Php Installing An Expansion
- rem : web app适配的秘密武器
- jquery高级应用之Deferred对象
- php7 读取php.ini[4]
- Mootools 1.2教程 正则表达式
- 批处理FINDSTR正则表达式用法实例分析
- PHP+Apache在Windows 9x下的安装和配置
- IIS 6 的 PHP 最佳配置方法
- 安装Apache和PHP的一些补充