php 模板引擎原理,php模板引擎的原理与简单实例

模板引擎其实就是将一个带有自定义标签的字符串,通过相应的规则解析,返回php可以解析的字符串,这其中正则的运用是必不可少的,所以要有一定的正则基础。

总体思想,引入按规则写好的模板,传递给标签解析类(_HtmlTag)进行解析,再把解析好的字符串传递给php进行解析渲染输出

首先定义了一个_HtmlTag类:class _HtmlTag{  protected $taglist = "if|elseif|else|loop|for|while|=|:=|:e|:html|:";  protected $string;  protected $tpldir;  function __construct($dir, $tpl) {    $this->findReg = "/\\{[ ]*($this->findReg)(\\s*[\\{\\}]+\\s*)?\\}/i";    $this->tpldir = $dir;    $this->tpl =$tpl;

}

}先解析下render方法

在render方法中对传入的字符串$s,进行相应的替换渲染,用到了extends方法,import方法,''开头的各种过滤方法,后面会一一进行详解.function render($s) {

$s = str_replace([''], ['{','}'], $s);  if (strpos($s, "{extends") !== false) {

$s = $this->_extends($s);

}

$s = preg_replace('/[\\n\\r]+/s', "\\n", $s);

$s = preg_replace('/\\r+/s', "", $s);

$s = preg_replace('/\\t+/s', "\\t", $s);

$this->string = str_replace(["\\{", "\\}"], ["\\HKH1", "\\HKH2"], $s);

preg_match_all("/\\{[ ]*(import)(\\s*[^\\{\\}]+\\s*)?\\}/i", $s, $d);  foreach($d[0] as $k => $v) {

call_user_func_array(array($this, "_import"), array($v, $d[1][$k], $d[2][$k]));

}  static $m = array("=" => "_defaultEcho", ":=" =>" _xssEcho", ":e" => "_htmlencodeEcho", ":" => "_echo", ":html" => "_htmldecodeEcho");

preg_match_all($this->findReg, $this->string, $d);  foreach ($d[0] as $k => $v) {    if (isset($m[$d[1][$k]])) {

$medth = $m[$d[1][$k]];

} else {

$medth = '_' . $d[1][$k];

}

call_user_func_array(array($this, $medth), array($v, $d[1][$k], $d[2][$k]));

}

}_extends方法

使用 个方法是为了判断是否有继承相应的模板文件,在子文件中用{extends 模板名},一般只要填写文件名,如index,系统会自动去构造完整的文件路径,一般在上一级目录,这个在realTpl()方法时会有详解function _extends($tpl) {

preg_match("/\\{\\s*extends\\s+([^\\{\\}]+?)\\s*\\}/i", $tpl, $d);  list($search, $arg) = $d;  if (stripos($arg, ".") !==0 ) {

$arg = '../' . $arg;

}

$file = $this->tpl->me->realTpl($arg . ".htm");

$basetpl = file_get_contents($file);

preg_match_all("/\\{block\\s+([^\\{\\}]+?)\\s*\\}(.+)\\{\\/block\\}/s", $tpl, $ds);  foreach($ds[1] as $n => $name) {

$basetpl = preg_replace("/\\{block\\s+name={$name}\\s*\\}/", $ds[2][$n], $basetpl);

}

$basetpl = preg_replace("/\\{block\\s+name=.+?\\}/", ' ', $basetpl);  return $basetpl;

}_import 方法

_import 方法是用来对{import 文件名}标签进行解析,默认也是上层目录,会把该文件的内容解析到当前标签位置,同时支持使用:函数名|参数1, 参数2,...的方式进行字符串的回调.这中的display方法后面会有详解function _import ($search, $tag, $arg) {

$arg = trim($arg);  if (stripos($arg, ".") !== 0) {

$arg = '../' . $arg;

}

$file = $this->tpl->me->realTpl($arg . ".htm");  if (file_exists($file)) {    $this->string = str_replace($search, file_get_contents($file), $this->string);  return;

} else {      if (stripos($file, "$") !== false) {          $this->string = str_replace($search, ' include $this->tpl->display("' . $arg . '"); ?>', $this->string);           return;

}      if (stripos($arg, '|') !== false) {         list($func, $tmp) = explode("|", trim($arg));

$kw = explode(', ', $tmp);

} else {

$func = trim($arg);

$kw = array();

}      if (function_exists($func) {

$tpl_str = call_user_func_array($func, $kw);         $this->string = str_replace($search, $tpl_str, $this->string);          return;

} else {        $this->string = str_replace($search, $arg, $this->string);      return;

}

system_error($this->tpldir . trim($arg) . ".htm不存在");

}

}现在来看一个标签函数_loop,将标签{loop $data $k $v}或{loop $data $v}替换,实现模板循环,其中的parseAttr方法接下来将详解function _loop($search, $tag, $arg) {

list($attr, $arg) = $this->parseAttr($arg);  $d = preg_split("/\\s+/", trim($arg));  if (count($d) == 3) {     $data = $d[0];     $k = $d[1];     $v = $d[2];     $s = " \\n if(!empty($data)) {\\n \\t foreach(" . $data . " as {$k} => {$v}){";

} elseif (count($d) == 2) {    $data = $d[0];    $v = $d[1];    $s = " \\n if(!empty($data)){\\n \\t

foreach(". $datsa . " as {$v}) {";

}  if (isset($attr['counter'])) {    $s = "\\n \\t\\t if (!isset({$attr['counter']})) { {$attr['counter']} = 0;} ?> \\n \\t\\t" . $s . "\\n \\t\\t{$attr['counter']}++; \\n ?>;

} else {    $s .= "?>";

}  $this->string = str_replace($search, $s, $this->string);  $this->string = str_replace("{/loop}", " \\t}\\n}?>", $this->string);

}parseAttr方法

该方法用来解析标签 的参数,返回的第一个参数是值形式字符串,第二个是键值数组,如{loop $data $k $v}返回$data $k $v 组成 的字符串和一个空数组,{if $k = $v}则返回空字符串和和数组[$k => $v];function parseAttr($s) {

$reg = '/([a-zA-Z0-9_])+\\s*=\\s*([a-zA-Z0-9_\\$]+)/i';

$arg = preg_replace($reg, '', $s);

preg_match_all($reg, $s, $d);

$arr = array();  foreach($d[1] as $key => $value) {

$arr[trim($value)] = trim($d[2][$key]);

}  return array($arr, $arg);

}_if 方法

将{if}{/if}标签解析成原生 的php,简单明了,不多解释function _if ($search, $tag, $arg) {

$replace[0] = " if($arg){?>";

$replace[1] = " }?>";  $this->string = str_replace(array($search, "{/$tag}"), $replace, $this->string);

}_else方法

将{else}解析成原生的phpfunction _else($search, $tag, $arg) {  $this->string = str_replace("{else}", "\\n" . ' } else {?>', $this->string);

}_elseif方法

将{elseif}解析成原生的phpfunction _elseif($search, $tag, $arg) {  $this->string = str_replace($search, " }elseif($arg){?>", $this->string);

}_for 方法function _for($search, $tag, $arg) {

$s = trim(trim(preg_replace('/\\s+/', ' ; ', $arg)), ';');  $this->string = str_replace($search, " for($s){?>", $this->string);  $this->string = str_replace("{/for}", " \\t\\n}?>", $this->string);

}_while方法function _while($search, $tag, $arg) {  $this->string = str_replace($search , " while($aeg){ ?>", $this->string);  $this->string = str_replace("{/while}", " \\t\\n} ?>", $this->string);

}_end方法

通过这个方法对其$this->string进行修改可以对变量进行如下标签定义:

{$val}{$arr[$key]}{$arr['key']}{:val()}{$arr.key}{$arr.$key}function _end() {  //{$val}标签解析

$this->string = preg_replace('/\\{(\\$\\w+.*)\\}/is', "=\\\\1;?>", $this->string);   //{:$val()}标签解析

$this->string = preg_replace('/\\{\\:\\s*(\\$?\\w+.*?)\\}/is', " =\\\\1;?>", $this->string);  //将$val[arg]解析成$val['arg']

$this->string = preg_replace('/\\$([_a-z]+\\w*)\\[([_a-z]+\\w*)\\]/is', "$\\\\1['\\\\2']", $this->string);  //支持点号访问数组。如array['key']可以用array.key访问

$this->string = preg_replace('/\\$([_a-z]+\\w*)\\.(\\$[_a-z]+\\w*)/is', "$\\\\1[\\\\2]", $this->string);  $this->string = preg_replace('/\\$([_a-z]+\\w*)\\.([_a-z]+\\w*)/is', "$\\\\1['\\\\2']", $this->string);  $this->string = preg_replace(array("/string);

}_result方法,做最后处理,返回字符串,_end方法在上面已经解释过了function result() {  $this->_end();  $this->_baseParse($this->stirng);  return str_replace(array("\\HKH1", "\\HKH2"), array("\\{", "\\}"), $this->string);

}

下面再来介绍一下几个过滤的方法_htmlencodeEcho方法

可以用此种形式对变量进行htmlspecialchars式的过滤spspecialchars函数后面会有介绍{:e $val}function _htmlencodeEcho($search, $tag, $arg) {  if (stripos($arg, '$')) {    $this->string = str_replace($search, " echo sphtmlspecialchars(!empty($arg)?$arg:''))?>", $this->string);

} else {    $this->string = str_replace($search, " echo sphtmlspecialchars($arg)?>", $this->string);

}

}_htmldecodeEcho方法_htmldecodeEcho($search, $tag, $arg) {  if (stripos($arg, '$')) {    $this->string = str_replace($search, " echo htmlspecialchars_decode(!empty($arg)?$arg:'')?>", $this->string);

} else {    $this->string = str_replace($search, " echo htmlspecialchars_decode($arg)?>", $this->string);

}

}_defaultEcho方法function _defaultEcho($search, $tag, $arg) {  if (stripos($arg, ',') == false) {

$arg . = ", ' ' ";    list($v, $default) = explode(",", $arg);    $this->string = str_replace($search, " echo empty($v)?$default:$v; ?>", $this->string);

}

}_xssEcho方法_xssEcho($search, $tag, $arg) {  $this->string = str_replace($search, " echo xssRemove($arg); ?>", $this->string);

}

_echo方法function _echo($search, $tag, $arg){  $this->string = str_replace($search, " echo $arg;?>", $this->string);

}_baseParse方法,这个对css和js的引入进行处理function _baseParse($s) {  if (strpos($s, "{loadCss") !== false) {

$s = $this->_loadCss($s);

}  if (strpos($s, "{loadJs") !== false) {

$s = $this->_loadJs($s);

}  return $s;

}_loadJs方法function _loadJs($tpl) {

preg_match_all('/\{loadJs\s+([^\{\}]+?)\s*\}/i', $tpl, $match);  include "jsmin.php";  foreach($match[1] as $k => $js) {

$jsstr = "";

$cdn = "";

$if (stripos($js, ',') !== false) {

$filename = "";

$md5 = "";

$js_content = "";        foreach(explode(',', $js) as $j) {

$filename .= basename($j, '.js') . ',';

$md5 .= self::fileMd5($j);          if (stripos($j, '.min.') == false) {

$js_content .= JSMin::minify(file_get_contents(WEB_ROOT . $j));

} else {

$js_content .= file_get_contents(WEB_ROOT . $j);

}

$js_content .= ';'

}

$md5 = md5($md5);

$filename = dirname($j) . '/' .trim($filename, ',') . '.js';      self::parseJs($js_content, $filename);

$jsstr = "";

} else {

$md5 = self::fileMd5($js);      if (stripos($js, ".min.") === false) {

$js = self::pareJs(JSMin::minify(file_get_contents(WEB_ROOT . $js)), dirname($js). '/' .basename($js, '.js') . '.min.js');

}

$jsstr = "";

}

$tpl = str_replace($match[0][$k], $jsstr, $tpl);

}  return $tpl;

}

_loadCss方法function _loadCss($tpl) {

preg_match_all('/\{loadCss\s+([^\{\}]+)\s*\}/i' , $tpl , $match);

$cdn = "";  foreach($match[1] as $k => $css) {

$cssstr = "";    if (stripos($css, ',') !== false) {

$filename = "";

$md5 = "";

$css_content = "";       foreach($explode(',', $css) as $css) {

$filename .= basename($css, '.css') . ',';

$md5 = self::fileMd5($css);

$css_content .= file_get_contents(WEB_ROOT .$css);

}

$md5 = md5($md5);

$filename = dirname($css) . '/' .trim($filename, ',') . '.css';        self::parseCss($css_content, $filename);

$cssstr = "";

} else {

$md5 = self::fileMd5($css);       if (stripos($css, ".min.") == false) {

$css = self::parseCss(file_get_contents(WEB_ROOT . $css), dirname($css) . '/' .basename($css, '.css') . '.min.css');

}

$cssstr .= "";

}

$tpl = str_replace($match[0][$k], $cssstr, $tpl);

}  return $tpl;

}上面两个函数都用到了各自的parseCss,和parseJs,让我们来看下static function parseCss($css_content, $filename) {

$css_content = preg_replace("/[\r\n\t]/", '', $css_content);

$css_content = preg_replace("/ +/", ' ', $css_content);

sp_file_pu_contents(WEB_ROOT . $filename, $css_content);  return $filename;

}static function parseJs($js, $filename) {

sp_file_put_content(WEB_ROOT . $filename, $js);  return $filename;

}

上面的_html类和他的方法对传入的字符串进行了标签到原生 Php的替换,可以传入相应的模板,也可以在其中自定义自己的过滤方法。下面我们再来看一个template类:定义这个类来对模板进行管理,这里会用到上面的_html类,基本定义如下,接下来会介绍其中的一些方法class template {  private $tpl_cache_dir;  public $ext = ".htm";  public $default_tpl_dir = false;  public $me;  function _construct($tpl_cache_dir, $me) {    $this->sets($tpl_cache_dir);    $this->me = $me;

}  function sets($tpl_cache_dir) {    $this->tpl_cache_dir = $tpl_cache_dir;    if (SP_DEBUG == 1) {

spmkdir($this->tpl_cache_dir);

}

}  function default_template($dir) {    $this->default_tpl_dir = $dir;

}

}getString方法

在之前 开启ob_start(),然后获取这之间的ob数据,试用于框架中function getString() {

$s = ob_get_contents();

ob_clean();  return $s;

}display方法function display($tpl, $return = 0, $script = SCRIPT) {

$tpl .= $this->ext;

$tpl_name = $this->tpl_cache_dir . $script . '_' . str_replace(['/', '\\\\'], '_', $tpl);  if (SP_DEBUG){    if (SP_DEBUG == 1 || (SP_DEBUG == 2 && !file_exists($tpl_name))) {      $this->compiles($tpl_name, $tpl);

}

}  return $tpl_name;

}compiles方法, 在这里使用了sp_file_put_contentsb函数会在后面介绍function compiles($cache_name, $tpl) {  if (!file_exists($tpl)) {    if (file_exists($this->default_tpl_dir . $tpl)) {

$html = file_get_contents($this->default_tpl_dir . $tpl);

} else {

spmkdir(dirname($tpl), '777');

file_get_contents($tpl, 这个是自动生成模板');

}

} else {

$html = file_get_contents($tpl);

}

$tag = new _HtmlTag(realpath(dirname($tpl) . '/../'), $this);

$tag->render($html);

$html = preg_replace_callback('//s', array(&$this, "make_magic_func"), $tag->result());

$html = preg_replace('/[\\n\\r]{1,}/s', "\\n", $html);

@unlink($cache_name);

sp_file_put_contents($cache_name, $thml);

}make_magic_func方法function make_magic_func($d) {

preg_match_all('/(\\w+)=\\s*(\\'|\\")([^\\'"]+)?\\2/m', $d[2], $dd);

$aa = array();

foreach($dd[1] as $i => $k) {

$vs = preg_replace('/([^\\-]*[<>]{1,1})\\s*(\\S+)?\\s*/', '\\1\\'\\2\\' ', $dd[3][$i]);

$vs = preg_replace('/=\\s*(\\S+)?\\s*/', '=\\'\\1\\'', $dd[3][$i]);

if (stripos($d[3][$i], '$') !== false) {

$vs = preg_replace('/\\$([^\\']+)\\s*/', '{$\\1}', $vs);

}

}

}注意两个类的相应方法都 定义好了,这其中用到的函数sp_file_pu_contents($file, $data)function sp_file_put_contents($file, $data) {

$dir = dirname($file);    if (is_writeable($dir)) {        return file_put_contents($file, $data);

} else {        throw new writeFail(sprintf("写入文件%s,失败,目录不可写", $file), 503);

}

}

js压缩类: jsmin.class.php

链接:http://pan.baidu.com/s/1kUBx0X5 密码:y5jb

将这两个 类定义在一个文件中,使用进进行相应的配置define("WEB_ROOT", dirname(__FILE__) . '/');使用文件准备

base.htm,main.htm,test.js,test1.js,test.css,test1.css,indx.php,im.htm

main.htm:{import ./im}

{block name=head}

{block name=body}

{block name=foot}base.htm{extends ./main}

{block head}

{loadCss test.css,test1.css}

{loop $data $k $v}

我是头部

{/loop}

{if $bb == 'aa'}

我是if 测试

{elseif $bb = 'bb'}

我是elesif测试

{else}

我是eles测试

{/if}

{for $i=0 $i<10 $i++}

我是for循环

{/for}

{while $con >5} $con--;?>

我是while循环

{/while}

{/block}

{block foot}

我是尾部

{loadJs test1.js,test.js}

{/block}im.htm我是import进来的index.php<?phpdefine ('WEB_ROOT',dirname(__FILE__) . '/');function sp_file_put_contents($file, $data) {

$dir = dirname($file);    if (is_writeable($dir)) {        return file_put_contents($file, $data);

} else {        throw new writeFail(sprintf("写入文件%s,失败,目录不可写", $file), 503);

}

}class _HtmlTag{    protected $taglist = "if|elseif|else|loop|for|while|=|:=|:e|:html|:";    protected $string;    protected $tpldir;    public $findReg;    function __construct($dir, $tpl) {        $this->findReg = "/\{[ ]*($this->taglist)(\s*[^\{\}]+\s*)?\}/i";        $this->tpldir = $dir;        $this->tpl =$tpl;

}    function render($s) {

$s = str_replace([''], ['{','}'], $s);        if (strpos($s, "{extends") !== false) {

$s = $this->_extends($s);

}

$s = preg_replace('/[\n\r]+/s', "\n", $s);

$s = preg_replace('/\r+/s', "", $s);

$s = preg_replace('/\t+/s', "\t", $s);        $this->string = str_replace(["\{", "\}"], ["\HKH1", "\HKH2"], $s);

preg_match_all("/\{[ ]*(import)(\s*[^\{\}]+\s*)?\}/i", $s, $d);        foreach($d[0] as $k => $v) {

call_user_func_array(array($this, "_import"), array($v, $d[1][$k], $d[2][$k]));

}        static $m = array("=" => "_defaultEcho", ":=" =>" _xssEcho", ":e" => "_htmlencodeEcho", ":" => "_echo", ":html" => "_htmldecodeEcho");

preg_match_all($this->findReg, $this->string, $d);        foreach ($d[0] as $k => $v) {            if (isset($m[$d[1][$k]])) {

$medth = $m[$d[1][$k]];

} else {

$medth = '_' . $d[1][$k];

}

call_user_func_array(array($this, $medth), array($v, $d[1][$k], $d[2][$k]));

}

}    function _extends($tpl) {

preg_match("/\{\s*extends\s+([^\{\}]+?)\s*\}/i", $tpl, $d);        list($search, $arg) = $d;        if (stripos($arg, ".") !==0 ) {

$arg = '../' . $arg;

}        //$file = $this->tpl->me->realTpl($arg . ".htm");

$file = $arg . ".htm";

$basetpl = file_get_contents($file);

preg_match_all("/\{block\s+([^\{\}]+?)\s*\}(.+?)\{\/block\}/s", $tpl, $ds);        foreach($ds[1] as $n => $name) {

$basetpl = preg_replace("/\{block\s+name={$name}\s*\}/", $ds[2][$n], $basetpl);

}

$basetpl = preg_replace("/\{block\s+name=.+?\}/", ' ', $basetpl);        return $basetpl;

}    function _import ($search, $tag, $arg) {

$arg = trim($arg);        if (stripos($arg, ".") !== 0) {

$arg = '../' . $arg;

}        //$file = $this->tpl->me->realTpl($arg . ".htm");

$file = $arg . ".htm";        if (file_exists($file)) {            $this->string = str_replace($search, file_get_contents($file), $this->string);            return;

} else {            if (stripos($file, "$") !== false) {            $this->string = str_replace($search, ' include $this->tpl->display("' . $arg . '"); ?>', $this->string);            return;

}        if (stripos($arg, '|') !== false) {            list($func, $tmp) = explode("|", trim($arg));

$kw = explode(', ', $tmp);

} else {

$func = trim($arg);

$kw = array();

}        if (function_exists($func)) {

$tpl_str = call_user_func_array($func, $kw);            $this->string = str_replace($search, $tpl_str, $this->string);            return;

} else {            $this->string = str_replace($search, $arg, $this->string);            return;

}

system_error($this->tpldir . trim($arg) . ".htm不存在");

}

}

function mytest(){        return $this->string;

}    function _baseParse($s) {        if (strpos($s, "{loadCss") !== false) {

$s = $this->_loadCss($s);

}        if (strpos($s, "{loadJs") !== false) {

$s = $this->_loadJs($s);

}        return $s;

}    function fileMd5($f) {        if (stripos($f, "http://") !== false) {            return md5($f);

}            return md5_file(WEB_ROOT . $f);

}    function _loadCss($tpl) {

preg_match_all('/\{loadCss\s+([^\{\}]+)\s*\}/i' , $tpl , $match);

$cdn = "";        foreach($match[1] as $k => $css) {

$cssstr = "";            if (stripos($css, ',') !== false) {

$filename = "";

$md5 = "";

$css_content = "";                foreach(explode(',', $css) as $css) {

$filename .= basename($css, '.css') . ',';

$md5 = self::fileMd5($css);

$css_content .= file_get_contents(WEB_ROOT .$css);

}

$md5 = md5($md5);

$filename = dirname($css) . '/' . trim($filename, ',') . '.css';                self::parseCss($css_content, $filename);

$cssstr = "";

} else {

$md5 = self::fileMd5($css);                    if (stripos($css, ".min.") == false) {

$css = self::parseCss(file_get_contents(WEB_ROOT . $css), dirname($css) . '/' .basename($css, '.css') . '.min.css');

}

$cssstr .= "";

}

$tpl = str_replace($match[0][$k], $cssstr, $tpl);

}        return $tpl;

}

function _loadJs($tpl) {

preg_match_all('/\{loadJs\s+([^\{\}]+?)\s*\}/i', $tpl, $match);        //var_dump($match);die;

include "jsmin.class.php";        foreach($match[1] as $k => $js) {

$jsstr = "";

$cdn = "";            if (stripos($js, ',') !== false) {

$filename = "";

$md5 = "";

$js_content = "";                foreach(explode(',', $js) as $j) {

$filename .= basename($j, '.js') . ',';

$md5 .= self::fileMd5($j);                    if (stripos($j, '.min.') === false) {

$js_content .= JSMin::minify(file_get_contents(WEB_ROOT . $j));

} else {

$js_content .= file_get_contents(WEB_ROOT . $j);

}

$js_content .= ';';

}

$md5 = md5($md5);

$filename = dirname($js) . '/' .trim($filename, ',') . '.js';                self::parseJs($js_content, $filename);

$jsstr = "";

} else {

$md5 = self::fileMd5($js);                if (stripos($js, ".min.") === false) {

$js = self::pareJs(JSMin::minify(file_get_contents(WEB_ROOT . $js)), dirname($js). '/' .basename($js, '.js') . '.min.js');

}

$jsstr = "";

}

$tpl = str_replace($match[0][$k], $jsstr, $tpl);

}        return $tpl;

}    static function parseCss($css_content, $filenme) {

$css_content = preg_replace("/[\r\n\t]/", '', $css_content);

$css_content = preg_replace("/ +/", ' ', $css_content);        // echo WEB_ROOT . $filenme;

sp_file_put_contents(WEB_ROOT . $filenme, $css_content);        return $filenme;

}    static function parseJs($js, $filenme) {

sp_file_put_contents(WEB_ROOT . $filenme, $js);        return $filenme;

}    function _loop($search, $tag, $arg) {        list($attr, $arg) = $this->parseAttr($arg);

$d = preg_split("/\s+/", trim($arg));        if (count($d) == 3) {

$data = $d[0];

$k = $d[1];

$v = $d[2];

$s = " \n if(!empty($data)) {\n \t foreach(" . $data . " as {$k} => {$v}){";

} elseif (count($d) == 2) {

$data = $d[0];

$v = $d[1];

$s = " \n if(!empty($data)){\n \t foreach(". $datsa . " as {$v}) {";

}        if (isset($attr['counter'])) {

$s = "\n\t\t  if (!isset({$attr['counter']})) { {$attr['counter']} = 0;} ?> \n \t\t" . $s . "\n \t\t{$attr['counter']}++; \n ?>";

} else {

$s .= "?>";

}        $this->string = str_replace($search, $s, $this->string);        $this->string = str_replace("{/loop}", " \t}\n}?>", $this->string);

}    function parseAttr($s) {

$reg = '/([a-zA-Z0-9_])+\s*=\s*([a-zA-Z0-9_\$]+)/i';

$arg = preg_replace($reg, '', $s);

preg_match_all($reg, $s, $d);

$arr = array();        foreach($d[1] as $key => $value) {

$arr[trim($value)] = trim($d[2][$key]);

}        return array($arr, $arg);

}    function _if ($search, $tag, $arg) {

$replace[0] = " if($arg){?>";

$replace[1] = " }?>";        $this->string = str_replace(array($search, "{/$tag}"), $replace, $this->string);

}    function _else($search, $tag, $arg) {        $this->string = str_replace("{else}", "\n" . ' } else {?>', $this->string);

}    function _elseif($search, $tag, $arg) {     $this->string = str_replace($search, " }elseif($arg){?>", $this->string);

}    function _for($search, $tag, $arg) {

$s = trim(trim(preg_replace('/\s+/', ' ; ', $arg)), ';');      $this->string = str_replace($search, " for($s){?>", $this->string);      $this->string = str_replace("{/for}", " \t\n}?>", $this->string);

}    function _while($search, $tag, $arg) {      $this->string = str_replace($search , " while($arg){ ?>", $this->string);      $this->string = str_replace("{/while}", " \t\n} ?>", $this->string);

}    function _end() {        //{$val}标签解析

$this->string = preg_replace('/\\{(\\$\\w+.*)\\}/is', "=\\\\1;?>", $this->string);        //{:$val()}标签解析

$this->string = preg_replace('/\\{\\:\\s*(\\$?\\w+.*?)\\}/is', " =\\\\1;?>", $this->string);        //将$val[arg]解析成$val['arg']

$this->string = preg_replace('/\\$([_a-z]+\\w*)\\[([_a-z]+\\w*)\\]/is', "$\\\\1['\\\\2']", $this->string);        //支持点号访问数组。如array['key']可以用array.key访问

$this->string = preg_replace('/\\$([_a-z]+\\w*)\\.(\\$[_a-z]+\\w*)/is', "$\\\\1[\\\\2]", $this->string);        $this->string = preg_replace('/\\$([_a-z]+\\w*)\\.([_a-z]+\\w*)/is', "$\\\\1['\\\\2']", $this->string);        $this->sring = preg_replace(array("/string);

}    function result() {        $this->_end();        $this->string = $this->_baseParse($this->string);        return str_replace(array("\\HKH1", "\\HKH2"), array("\\{", "\\}"), $this->string);

}

}

$data = ['aa','bb','cc'];

$bb = 'aa';

$con = 11;

$tag = new _HtmlTag('./index', '');

$str = file_get_contents('base.htm');

$tag->render($str);

$html = $tag->result();

var_dump($html);echo '----------------------------';

sp_file_put_contents("./index.html", $html);include "index.html";运行index.php查看结果

AAffA0nNPuCLAAAAAElFTkSuQmCC

Paste_Image.png

AAffA0nNPuCLAAAAAElFTkSuQmCC

Paste_Image.png总结

我们来总结一下这个类的使用过程,先实例话template类,调用template::display()方法,其中会调用template::compiles()方法,这个方法会实例化_HhtmlTag类,调用_HtmlTag::render方法,在这个方法里,对传入的带字符串进行一个结构的完整化,包括调用_HtmlTag::_extends,_HtmlTag::_import,_HtmlTag::_loop,_HtmlTag::_if,_HtmlTag::elseif,_HtmlTag::else,_HtmlTag::_for,_HtmlTag::while接着调用_HtmlTag::result方法,里面调用_HtmlTag::_end方法对变量进行php原生化和_HtmlTag::_baseParse()引入css和js,最后返回解析好的完整模板字符串。

作者:hopevow

链接:https://www.jianshu.com/p/622004b0b93b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值