+ -
当前位置:首页 → 问答吧 → PHP 小巧简单带静态缓存的模版类

PHP 小巧简单带静态缓存的模版类

时间:2013-05-03

来源:互联网

class Template
{
        public $caching = false; //模版缓存开关 true | false

        private $_config = array(
                'path'                        => 'template', //模版文件路径
                'compile_path'        => 'template_compile', //模版编译文件路径
                'suffix'                => '.html', //模版后缀
                'cache_path'        => 'cache', //缓存路径
                'cache_name'        => '' //缓存名称
        );

        private $_templateName;

        private $_templateVars;

        private static $_instance;

        private function __construct(){}

        public static function getInstance()
        {
                if (empty(self::$_instance)) {
                        self::$_instance = new self;
                }
                return self::$_instance;
        }

        public function setConfig($config)
        {
                if (!empty($config)) {
                        $config = array_merge($this->_config, $config);
                }
                $this->_config = array_change_key_case($config);
                return $this;
        }

        /*
         * 模版变量赋值
         * @param mixed 变量名称 支持批量设置,如: array('title' => '', 'name' => '');
     * @param mixed 变量值 如果为批量设置方式则无效
         */
        public function assign($vars, $value = '')
        {
                if (is_array($vars)) {
                        foreach ($vars as $key => $val) {
                                if (!empty($key)) $this->_templateVars[$key] = $val;
                        }
                } else {
                        if (!empty($vars)) $this->_templateVars[$vars] = $value;
                }
        }

        private function _templatePath($templateName)
        {
                return $this->_config['path'].'/'.$templateName.$this->_config['suffix'];
        }

        private function _compilePath($templateName)
        {
                return $this->_config['compile_path'].'/'.$templateName.'.compile';
        }

        //使用__var__这样的命名尽量避免污染模版变量
        public function fetch($__templateName__)
        {
                $this->_compile($__templateName__);
                if (!empty($this->_templateVars)) extract($this->_templateVars);
                ob_start();
                $__file__ = $this->_compilePath($__templateName__);
                if (is_file($__file__)) {
                        include $this->_compilePath($__templateName__);
                        $content = ob_get_clean();
                        return $content;
                } else {
                        throw new Exception(__METHOD__.'找不到模板编译文件: '.$__file__);
                }
        }

        private function _compile($templateName)
        {
                $templateFile = $this->_templatePath($templateName);
                $compileFile = $this->_compilePath($templateName);
                if (!is_file($compileFile) || @filemtime($templateFile) > @filemtime($compileFile)) {
                        if (is_file($templateFile)) {
                                $content = file_get_contents($templateFile);
                                $content = self::_parse($content);
                                self::_makeDir(dirname($compileFile));
                                file_put_contents($compileFile, $content);
                        } else {
                                echo '模板文件不存在: '.$templateFile;
                                throw new Exception(__METHOD__.'找不到模板文件: '.$templateFile);
                        }
                }
        }

        private static function _parse($content)
        {
                //过滤模板<!-- -->注释
                $content = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $content);
                //模板包含模板
                $content = preg_replace("/\{template\sfile=(\"?)([\w|-]+)\\1\}/i", "<?php echo \$this->fetch('\\2'); ?>", $content);
                //PHP标签
                $content = preg_replace("/\{php\s+(.+)\}/", "<?php \\1?>", $content);
                //echo变量
                $content = preg_replace("/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $content);
                //echo常量
                $content = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s", "<?php echo \\1;?>", $content);
                //echo函数
                $content = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/","<?php echo \\1;?>", $content);
                //if
                $content = preg_replace("/\{if\s+(.+?)\}/", "<?php if(\\1) { ?>", $content);
                //else
                $content = preg_replace("/\{else\}/", "<?php } else { ?>", $content);
                //elseif
                $content = preg_replace("/\{elseif\s+(.+?)\}/", "<?php } elseif (\\1) { ?>", $content);
                //end if
                $content = preg_replace("/\{\/if\}/", "<?php } ?>", $content);
                //foreach
                $content = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/", "<?php if(is_array(\\1)) foreach(\\1 AS \\2) { ?>", $content);
                $content = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/","<?php if(is_array(\\1)) foreach(\\1 AS \\2 => \\3) { ?>", $content);
                $content = preg_replace("/\{\/loop\}/", "<?php } ?>", $content);
                //echo foreach 变量
                $content = preg_replace("/\{(\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es", "self::_quote('<?php echo \\1;?>')", $content);
                return $content;
        }

        private static function _quote($var)
        {
                return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
        }

        /*
         * 模版输出
         * @param string 如果之前有缓存isCache(template)判断,可留空
         */
        public function display($templateName = '')
        {
                if (!empty($this->_templateName)) $templateName = $this->_templateName;
                if ($this->caching == true) {
                        $templateFile = $this->_templatePath($templateName);
                        $cacheFile = $this->_getCacheFile();
                        if (!$this->_checkCache($templateFile, $cacheFile)) {
                                $content = $this->fetch($templateName);
                                self::_makeDir(dirname($cacheFile));
                                file_put_contents($cacheFile, $content);
                        } else {
                                $content = file_get_contents($cacheFile);
                        }
                        echo $content;
                } else {
                        echo $this->fetch($templateName);
                }
        }

        private function _getCacheFile()
        {
                if (!$this->_config['cache_name']) $this->_config['cache_name'] = $this->_templateName;
                return $this->_config['cache_path'].'/'.$this->_config['cache_name'].'.html';
        }

        private static function _checkCache($templateFile, $cacheFile)
        {
                if (!is_file($cacheFile) || @filemtime($templateFile) > @filemtime($cacheFile)) {
                        return false;
                }
                return true;
        }

        public function isCache($templateName)
        {
                $this->_templateName = $templateName;
                if ($this->caching == false) return false;
                $templateFile = $this->_templatePath($templateName);
                $cacheFile = $this->_getCacheFile();
                if (!$this->_checkCache($templateFile, $cacheFile)) return false;
                return true;
        }

        /*
         * 清除模版HTML缓存文件
         * @param string 参数同glob 默认为当前模版
         * [url=http://bbs.phpchina.com/home.php?mod=space&uid=987628]@Return[/url] bool
         */
        public function clearCache($search = '')
        {
                if (!empty($search)) {
                        $files = glob($this->_config['cache_path'].'/'.$search.'.html');
                        if (!empty($files)) {
                                foreach ($files as $file) {
                                        if (is_file($file)) unlink($file);
                                }
                                return true;
                        }
                }
                return is_file($this->_getCacheFile()) ? unlink($this->_getCacheFile()) : false;
        }

        private static function _makeDir($dir, $mode = 0777)
        {
                if (!is_dir($dir)) {
                        self::_makeDir(dirname($dir), $mode);
                        return mkdir($dir, $mode);
                }
                return true;
        }
}


$Tpl = Template::getInstance();
$Tpl->setConfig(array('path' => 'tpl'));
$Tpl->setConfig(array('compile_path' => 'tpl_c'));
$Tpl->setConfig(array('cache_path' => 'tpl_cache'));

//常规赋值
$Tpl->assign('author', '作者');
//批量赋值
$Tpl->assign(array('title' => '标题', 'content' => '内容'));

//使用try来捕获类可能存在的错误
try{

        //开启缓存(永久缓存)
        $Tpl->caching = true; // *注意 caching 必须开启,下面的缓存才有效

        $page = 1; //这里表示分页$_GET['page']

        //设置缓存文件名
        $Tpl->setConfig(array('cache_name' => 'index-'.$page)); //根据分页来缓存

        //检查缓存是否存在
        if (!$Tpl->isCache('index')) { //这里的index为模版名,下面的display就不用再传递
                echo '写缓存...并且一系列的操作……';
        }
        $Tpl->display();

} catch (Exception $e) {
        echo '<p>'.$e->getMessage().'</p>';
}

//清除缓存
//比如在后台操作
//后台可能模板类被重新实例化 (配置前台缓存的目录)
$Tpl->setConfig(array('cache_path' => 'tpl_cache'));

//参数同php glob()函数
$Tpl->clearCache('index-1'); //清除index-1缓存文件
$Tpl->clearCache('index-*'); //清除index-为前缀的缓存文件



模版语法:http://www.yytweb.com/a/41.html

作者: gyyst   发布时间: 2013-05-03

看着写那么一大堆assign,就相当不爽,浪费太多时间在没有意义的assign上了。远不如php include来得方便

作者: xuer   发布时间: 2013-05-04

xuer 发表于 2013-5-4 23:04
看着写那么一大堆assign,就相当不爽,浪费太多时间在没有意义的assign上了。远不如php include来得方便 ...

.      受打击了

作者: gyyst   发布时间: 2013-05-05

嗯还可以简化一下额 呵呵

作者: Frank_Luo   发布时间: 2013-05-14