模板引擎-实现

1.目录结构

Project
|-view
|  |-page.html
|  |-show.html
|-cache
|-Tpl.php
|-index.php

view

存放 HTML模板文件

cache

存放由 HTML模板文件 生成的 PHP缓存文件

Tpl.php

模板引擎类,用于将 HTML模板文件 中的 {模板语句} 替换为 <?=PHP语句;?>,并在 cache文件夹 生成 PHP缓存文件,然后包含 PHP缓存文件 以显示出来

index.php

利用 模板引擎类 显示页面

2.代码实现

访问 index.php 时,将通过 Tpl.php 中的 模板引擎类 在 cache文件夹 中生成 page.html.php 和 show.html.php,并包含它们将内容显示出来

index.php

<?php
include 'Tpl.php';

$tpl = new Tpl();

// 设置变量
$tpl->assign('title', 'title');
$tpl->assign('show', 'HI,HACKER!');
$tpl->assign('data', ['HACK', 'ME']);

// 显示页面
$tpl->display('page.html', true);

Tpl.php

<?php
class Tpl {
    // HTML模板文件的路径
    protected $viewDir = './view/';
    // 生成的PHP缓存文件的路径
    protected $cacheDir = './cache/';
    // PHP缓存文件的过期时间
    protected $lifetime = 3600;
    // 存放变量的数组
    protected $vars = [];

    // 存放变量
    function assign($name, $value) {
        $this->vars[$name] = $value;
    }

    /*
     * 显示PHP缓存文件
     * 参数1:HTML模板文件名
     * 参数2:HTML模板文件是否需要包含
    */
    function display($viewName, $isInclude) {
        // 模板文件全路径
        $viewPath = $this->viewDir.$viewName;
        // 缓存文件全路径
        $cahePath = $this->cacheDir.$viewName.'.php';

        // PHP缓存文件不存在则生成PHP缓存文件
        if (!file_exists($cahePath)) {
            $php = $this->compile($viewPath);
            file_put_contents($cahePath, $php);
        }
        // PHP缓存文件超时则需要重新生成PHP缓存文件
        else {
            $isTimeout = (filectime($cahePath) + $this->lifetime) > time() ? false : true;
            if ($isTimeout) {
                $php = $this->compile($viewPath);
                file_put_contents($cahePath, $php);
            }
        }

        // 需要包含则解析变量并包含PHP缓存文件
        if ($isInclude) {
            extract($this->vars);
            include $cahePath;
        }
    }

    // 生成PHP缓存文件
    protected function compile($viewPath) {
        // 获取HTML模板文件内容
        $html = file_get_contents($viewPath);
        // \1为第一个捕获组匹配到的内容
        $array = [
            '{$%%}'=>'<?=$\1;?>',
            '{foreach %%}'=>'<?php foreach (\1):?>',
            '{/foreach}'=>'<?php endforeach;?>',
            '{include %%}'=>''
        ];

        foreach ($array as $key=>$value) {
            /*
             * 转义并生成正则
             * #包裹表示正则的/不需要转义
             * (.+?)表示一个懒惰匹配的捕获组
            */
            $pattern = '#'.str_replace('%%', '(.+?)', preg_quote($key)).'#';
            // 对HTML模板文件内容进行正则替换,include特殊情况要用回调函数处理
            if (strstr($pattern, 'include')) {
                $html = preg_replace_callback($pattern, [$this, 'parseInclude'], $html);
            }
            else {
                $html = preg_replace($pattern, $value, $html);
            }
        }
        return $html;
    }

    // 处理include,生成要包含进来的HTML模板文件的PHP缓存文件
    protected function parseInclude($data) {
        /*
         * 生成要包含进来的HTML模板文件的PHP缓存文件
         * $data[0]为匹配到的{include show.html}
         * $data[1]为第一个捕获组匹配到的show.html
        */
        $this->display($data[1], false);
        $cachePath = $this->cacheDir.$data[1].'.php';
        return '<?php include "'.$cachePath.'";?>';
    }
}

page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{$title}</title>
</head>
<body>
    {include show.html}
    {foreach $data as $value}
        {$value}<br>
    {/foreach}
</body>
</html>

show.html

<div>{$show}</div>
posted @ 2023-04-24 22:20  Hacker&Cat  阅读(34)  评论(0编辑  收藏  举报