php初学(六) --------------- 自制mvc框架(模板引擎)

一般简单的mvc框架由模板引擎,自动加载类,路由自定义三部分组成。

这里主要讲述模板引擎。

模板引擎主要的原理是引入文件,之后使用正则表达式替换模板里的语句,再把模板渲染出来。

比如访问index.php,先引入Template.php模板引擎文件(引入编译类Compile.php),然后使用渲染函数(show())渲染模板(member.html)。

index.php

<?php

include_once './Template.php';
$tpl = new Template();
$tpl->assign('data', 'hello');
$tpl->assign('person', 'world!');
$tpl->assign('arr1', array('123','456','789'));
$tpl->assign('arr2', array('abc', 'def', 'ghi'));
$tpl->assign('a', '2');
$tpl->show('member');

?>

Template.php

<?php
/**
* 模板引擎基础类
*/
class Template
{
    private $config = array(
        'suffix' => '.html',      // 设置模板文件的后缀
        'templateDir' => 'template/',    // 设置模板所在的文件夹
        'compileDir' => 'cache/',    // 设置编译后存放的目录
        'cache_html' => false,    // 是否需要编译成静态的HTML文件
        'suffix_cache' => '.html',    // 设置编译文件的后缀
        'cache_time' => 7200,    //  多长时间自动更新,单位秒
        'php_turn' => true,   // 是否支持原生PHP代码
        'cache_control' => 'control.dat',
        'debug' => false,
    );
    private static $instance = null;
    private $value = array();   // 值栈
    private $compileTool;   // 编译器
    public $file;     // 模板文件名,不带路径
    public $debug = array();   // 调试信息
    private $controlData = array();
    public function __construct($config = array())
    {
        $this->debug['begin'] = microtime(true);
        $this->config = $config + $this->config;
        if (! is_dir($this->config['templateDir'])) {
            exit("模板目录不存在!");
        }
        if (! is_dir($this->config['compileDir'])) {
            mkdir($this->config['compileDir'], 0770);
        }
        $this->getPath();
        include './Compile.php';
    }
    /**
    *获取绝对路径
    */
    public function getPath() {
        $this->config['templateDir'] = strtr(realpath($this->config['templateDir']), '\\', '/').'/';
        $this->config['compileDir'] = strtr(realpath($this->config['compileDir']), '\\', '/').'/';
    }
    /**
    *取得模板引擎的实例
    */
    public static function getInstance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    /* 设置模板引擎参数 */
    public function setConfig($key, $value = null) {
        if (is_array($key)) {
            $this->config = $key + $this->config;
        }else {
            $this->config[$key] = $value;
        }
    }
    /* 获取当前模板引擎配置,仅供调试使用 */
    public function getConfig($key = null) {
        if ($key) {
            return $this->config[$key];
        }else {
            return $this->config;
        }
    }
    /**
    *注入单个变量
    */
    public function assign($key, $value) {
        $this->value[$key] = $value;
    }
    /**
    *注入数组变量
    */
    public function assignArray($array) {
        if (is_array($array)) {
            foreach($array as $k => $v) {
                $this->value[$k] = $v;
            }
        }
    }
    /**
     * 获取模板文件完整路径
     */
    public function path() {
        return $this->config['templateDir'].$this->file.$this->config['suffix'];
    }
    /**
    *判断是否开启了缓存
    */
    public function needCache() {
        return $this->config['cache_html'];
    }
    /**
    *是否需要重新生成静态文件
    */
    public function reCache($file) {
        $flag = true;
        $compileFile = $this->config['compileDir'].md5($file).'.php';
        $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache'];
        if ($this->config['cache_html'] === true) {
            $timeFlag = (time() - @filemtime($cacheFile)) < $this->config['cache_time'] ? true : false;
            if (is_file($cacheFile) && filesize($cacheFile) > 1 && $timeFlag && filemtime($compileFile) >= filemtime($this->path())) {
                $flag = false;
            }else {
                $flag = true;
            }
        }
        return $flag;
    }
    /**
    *显示模板
    */
    public function show($file) {
        $this->file = $file;
        if (! is_file($this->path())) {
            exit('找不到对应的模板!');
        }
        $compileFile = $this->config['compileDir'].md5($file).'.php';
        $cacheFile = $this->config['compileDir'].md5($file).$this->config['suffix_cache'];
        extract($this->value, EXTR_OVERWRITE);
        if ($this->config['cache_html'] === true) { // 开启缓存的处理逻辑
            if ($this->reCache($file) === true) { // 需要更新缓存的处理逻辑
                $this->debug['cached'] = 'false';
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                if ($this->needCache()) {ob_start();} // 打开输出控制缓冲
                if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                    $this->compileTool->value = $this->value;
                    $this->compileTool->compile();
                    include $compileFile;
                }else {
                    include $compileFile;
                }
                if ($this->needCache()) {
                    $message = ob_get_contents(); // 获取输出缓冲中的内容(在include编译文件的时候就有输出了)
                    file_put_contents($cacheFile, $message);
                }
            }else {
                readfile($cacheFile);
                $this->debug['cached'] = 'true';
            }
        }else {
            if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                $this->compileTool->value = $this->value;
                $this->compileTool->compile();
                include $compileFile;
            }else {
                include $compileFile;
            }
        }
        $this->debug['spend'] = microtime(true) - $this->debug['begin'];
        $this->debug['count'] = count($this->value);
        //$this->debug_info();
    }
    public function debug_info() {
        if ($this->config['debug'] === true) {
            echo PHP_EOL, '---------debug info---------', PHP_EOL;
            echo "程序运行日期:", date("Y-m-d H:i:s"), PHP_EOL;
            echo "模板解析耗时:", $this->debug['spend'], '秒', PHP_EOL;
            echo '模板包含标签数目:', $this->debug['count'], PHP_EOL;
            echo '是否使用静态缓存:', $this->debug['cached'], PHP_EOL;
            echo '模板引擎实例参数:', var_dump($this->getConfig());
        }
    }
    /**
    *清理缓存的HTML文件
    */
    public function clean($path = null) {
        if ($path === null) {
            $path = $this->config['compileDir'];
            $path = glob($path.'* '.$this->config['suffix_cache']);
        }else {
            $path = $this->config['compileDir'].md5($path).$this->config['suffix_cache'];
        }
        foreach((array)$path as $v) {
            unlink($v);
        }
    }
}

?>

Compile.php

<?php

class Compile
{
    private $template;   // 待编译的文件
    private $content;   // 需要替换的文件
    private $comfile;   // 编译后的文件
    private $left = '{';   // 左定界符
    private $right = '}';   // 右定界符
    private $value = array();   // 值栈
    private $phpTurn;
    private $T_P = array();   // 匹配正则数组
    private $T_R = array();   // 替换数组
    public function __construct($template, $compileFile, $config) {
        $this->template = $template;
        $this->comfile = $compileFile;
        $this->content = file_get_contents($template);
        if ($config['php_turn'] === true) {
            $this->T_P[] = "#<\?(=|php|)(.+?)\?#is";
            $this->T_R[] = "&lt;?\1\2?&gt;";
        }
        // 变量匹配
        // \x7f-\xff表示ASCII字符从127到255,其中\为转义,作用是匹配汉字
        $this->T_P[] = "#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#";
        // foreach标签盘匹配
        $this->T_P[] = "#\{(loop|foreach)\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\}#i";
        $this->T_P[] = "#\{\/(loop|foreach|if)\}#";
        $this->T_P[] = "#\\$(k|v)\b.*?<#";
        //$this->T_P[] = "#\{*\\$(k|v)\}#";//\{.*?\$(k|v)\b.*?\}
        // if else标签匹配
        $this->T_P[] = "#\{if (.*?)\}#";
        $this->T_P[] = "#\{(else if|elseif) (.*?)\}#";
        $this->T_P[] = "#\{else\}#";
        $this->T_P[] = "#\{(\#|\*)(.*?)(\#|\*)\}#";

        $this->T_R[] = "<?php echo \$this->value['\\1']; ?>";
        $this->T_R[] = "<?php foreach ((array)\$this->value['\\2'] as \$k => \$v) {  ?>";
        $this->T_R[] = "<?php  } ?>";
        $this->T_R[] = "<?php echo \$\\1.'<'?>";
        $this->T_R[] = "<?php if(\\1){ ?>";
        $this->T_R[] = "<?php }elseif(\\2){ ?>";
        $this->T_R[] = "<?php }else{ ?>";
        $this->T_R[] = "";
    }
    public function compile() {
        $this->c_var();
        //$this->c_staticFile();
        file_put_contents($this->comfile, $this->content);
    }
    public function c_var() {
        $this->content = preg_replace($this->T_P, $this->T_R, $this->content);
    }
    /* 对引入的静态文件进行解析,应对浏览器缓存 */
    public function c_staticFile() {
        $this->content = preg_replace('#\{\!(.*?)\!\}#', '<script src=\1'.'?t='.time().'></script>', $this->content);
    }
    public function __set($name, $value) {
        $this->$name = $value;
    }
    public function __get($name) {
        return $this->$name;
    }
}

?>

member.html

<html>
{$data},{$person}
<br/>列表一:<br/>
<ul>
{foreach $arr1}
<li> $k  </li>
{/foreach}
</ul>
<br/>列表二:<br/>
<ul>
{loop $arr2}
<li>$v</li>
{/loop}
</ul>
{if $a == '1'} <h1>a等于1</h1>
{elseif $a == '2'}<h2>等于2</h2>
{else}<h3>不等于1也不等于2</h3>
{/if}
</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值