模板引擎类轻、灵活、快速、安全,它编译模板以优化 PHP 代码。
下面我将为您提供完整的源代码和如何使用模板引擎类的示例。
为什么我需要模板引擎?
模板引擎使设计代码远离应用程序代码,仅此原因就是好的做法,并且遵循许多设计模式。使用模板引擎完全取决于您,如果您希望保持代码干净整洁,那么使用模板引擎是理想的选择。
如果您正在使用 MVC 模式,那么使用模板引擎是一个好主意。
代码
创建一个新文件并命名它Template.php并添加:
<?php class Template {static $blocks = array();static $cache_path = 'cache/';static $cache_enabled = FALSE;static function view($file, $data = array()) {$cached_file = self::cache($file);extract($data, EXTR_SKIP);require $cached_file;}static function cache($file) {if (!file_exists(self::$cache_path)) {mkdir(self::$cache_path, 0744);}$cached_file = self::$cache_path . str_replace(array('/', '.html'), array('_', ''), $file . '.php');if (!self::$cache_enabled || !file_exists($cached_file) || filemtime($cached_file) < filemtime($file)) {$code = self::includeFiles($file);$code = self::compileCode($code);file_put_contents($cached_file, '<?php class_exists('' . __CLASS__ . '') or exit; ?>' . PHP_EOL . $code);}return $cached_file;}static function clearCache() {foreach(glob(self::$cache_path . '*') as $file) {unlink($file);}}static function compileCode($code) {$code = self::compileBlock($code);$code = self::compileYield($code);$code = self::compileEscapedEchos($code);$code = self::compileEchos($code);$code = self::compilePHP($code);return $code;}static function includeFiles($file) {$code = file_get_contents($file);preg_match_all('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', $code, $matches, PREG_SET_ORDER);foreach ($matches as $value) {$code = str_replace($value[0], self::includeFiles($value[2]), $code);}$code = preg_replace('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', '', $code);return $code;}static function compilePHP($code) {return preg_replace('~{%s*(.+?)s*%}~is', '<?php ?>', $code);}static function compileEchos($code) {return preg_replace('~{{s*(.+?)s*}}~is', '<?php echo ?>', $code);}static function compileEscapedEchos($code) {return preg_replace('~{{{s*(.+?)s*}}}~is', '<?php echo htmlentities(, ENT_QUOTES, 'UTF-8') ?>', $code);}static function compileBlock($code) {preg_match_all('/{% ?block ?(.*?) ?%}(.*?){% ?endblock ?%}/is', $code, $matches, PREG_SET_ORDER);foreach ($matches as $value) {if (!array_key_exists($value[1], self::$blocks)) self::$blocks[$value[1]] = '';if (strpos($value[2], '@parent') === false) {self::$blocks[$value[1]] = $value[2];} else {self::$blocks[$value[1]] = str_replace('@parent', self::$blocks[$value[1]], $value[2]);}$code = str_replace($value[0], '', $code);}return $code;}static function compileYield($code) {foreach(self::$blocks as $block => $value) {$code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code);}$code = preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code);return $code;}}?><?php class Template { static $blocks = array(); static $cache_path = 'cache/'; static $cache_enabled = FALSE; static function view($file, $data = array()) { $cached_file = self::cache($file); extract($data, EXTR_SKIP); require $cached_file; } static function cache($file) { if (!file_exists(self::$cache_path)) { mkdir(self::$cache_path, 0744); } $cached_file = self::$cache_path . str_replace(array('/', '.html'), array('_', ''), $file . '.php'); if (!self::$cache_enabled || !file_exists($cached_file) || filemtime($cached_file) < filemtime($file)) { $code = self::includeFiles($file); $code = self::compileCode($code); file_put_contents($cached_file, '<?php class_exists('' . __CLASS__ . '') or exit; ?>' . PHP_EOL . $code); } return $cached_file; } static function clearCache() { foreach(glob(self::$cache_path . '*') as $file) { unlink($file); } } static function compileCode($code) { $code = self::compileBlock($code); $code = self::compileYield($code); $code = self::compileEscapedEchos($code); $code = self::compileEchos($code); $code = self::compilePHP($code); return $code; } static function includeFiles($file) { $code = file_get_contents($file); preg_match_all('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', $code, $matches, PREG_SET_ORDER); foreach ($matches as $value) { $code = str_replace($value[0], self::includeFiles($value[2]), $code); } $code = preg_replace('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', '', $code); return $code; } static function compilePHP($code) { return preg_replace('~{%s*(.+?)s*%}~is', '<?php ?>', $code); } static function compileEchos($code) { return preg_replace('~{{s*(.+?)s*}}~is', '<?php echo ?>', $code); } static function compileEscapedEchos($code) { return preg_replace('~{{{s*(.+?)s*}}}~is', '<?php echo htmlentities(, ENT_QUOTES, 'UTF-8') ?>', $code); } static function compileBlock($code) { preg_match_all('/{% ?block ?(.*?) ?%}(.*?){% ?endblock ?%}/is', $code, $matches, PREG_SET_ORDER); foreach ($matches as $value) { if (!array_key_exists($value[1], self::$blocks)) self::$blocks[$value[1]] = ''; if (strpos($value[2], '@parent') === false) { self::$blocks[$value[1]] = $value[2]; } else { self::$blocks[$value[1]] = str_replace('@parent', self::$blocks[$value[1]], $value[2]); } $code = str_replace($value[0], '', $code); } return $code; } static function compileYield($code) { foreach(self::$blocks as $block => $value) { $code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code); } $code = preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code); return $code; } } ?><?php class Template { static $blocks = array(); static $cache_path = 'cache/'; static $cache_enabled = FALSE; static function view($file, $data = array()) { $cached_file = self::cache($file); extract($data, EXTR_SKIP); require $cached_file; } static function cache($file) { if (!file_exists(self::$cache_path)) { mkdir(self::$cache_path, 0744); } $cached_file = self::$cache_path . str_replace(array('/', '.html'), array('_', ''), $file . '.php'); if (!self::$cache_enabled || !file_exists($cached_file) || filemtime($cached_file) < filemtime($file)) { $code = self::includeFiles($file); $code = self::compileCode($code); file_put_contents($cached_file, '<?php class_exists('' . __CLASS__ . '') or exit; ?>' . PHP_EOL . $code); } return $cached_file; } static function clearCache() { foreach(glob(self::$cache_path . '*') as $file) { unlink($file); } } static function compileCode($code) { $code = self::compileBlock($code); $code = self::compileYield($code); $code = self::compileEscapedEchos($code); $code = self::compileEchos($code); $code = self::compilePHP($code); return $code; } static function includeFiles($file) { $code = file_get_contents($file); preg_match_all('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', $code, $matches, PREG_SET_ORDER); foreach ($matches as $value) { $code = str_replace($value[0], self::includeFiles($value[2]), $code); } $code = preg_replace('/{% ?(extends|include) ?'?(.*?)'? ?%}/i', '', $code); return $code; } static function compilePHP($code) { return preg_replace('~{%s*(.+?)s*%}~is', '<?php ?>', $code); } static function compileEchos($code) { return preg_replace('~{{s*(.+?)s*}}~is', '<?php echo ?>', $code); } static function compileEscapedEchos($code) { return preg_replace('~{{{s*(.+?)s*}}}~is', '<?php echo htmlentities(, ENT_QUOTES, 'UTF-8') ?>', $code); } static function compileBlock($code) { preg_match_all('/{% ?block ?(.*?) ?%}(.*?){% ?endblock ?%}/is', $code, $matches, PREG_SET_ORDER); foreach ($matches as $value) { if (!array_key_exists($value[1], self::$blocks)) self::$blocks[$value[1]] = ''; if (strpos($value[2], '@parent') === false) { self::$blocks[$value[1]] = $value[2]; } else { self::$blocks[$value[1]] = str_replace('@parent', self::$blocks[$value[1]], $value[2]); } $code = str_replace($value[0], '', $code); } return $code; } static function compileYield($code) { foreach(self::$blocks as $block => $value) { $code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code); } $code = preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code); return $code; } } ?>
请记住更新$cache_enabled和$cache_path变量,缓存当前已禁用用于开发目的,您可以在代码已准备就绪时启用此功能。
如何使用
创建一个新文件并命名index.php :
<?phpinclude 'Template.php';Template::view('index.html');?><?php include 'Template.php'; Template::view('index.html'); ?><?php include 'Template.php'; Template::view('index.html'); ?>
创建新的 HTML 文件并命名 layout.html :
<!DOCTYPE html><html><head><title>{% yield title %}</title><meta charset="utf-8"></head><body>{% yield content %} </body></html><!DOCTYPE html><html> <head> <title>{% yield title %}</title> <meta charset="utf-8"> </head> <body> {% yield content %} </body></html><!DOCTYPE html><html> <head> <title>{% yield title %}</title> <meta charset="utf-8"> </head> <body> {% yield content %} </body></html>
这是我们将用于此示例的布局。
现在创建index.html
{% extends layout.html %}{% block title %}Home Page{% endblock %}{% block content %}<h1>Home</h1><p>Welcome to the home page!</p>{% endblock %}{% extends layout.html %} {% block title %}Home Page{% endblock %} {% block content %}<h1>Home</h1><p>Welcome to the home page!</p>{% endblock %}{% extends layout.html %} {% block title %}Home Page{% endblock %} {% block content %}<h1>Home</h1><p>Welcome to the home page!</p>{% endblock %}
现在给它一个尝试, 导航到index. php文件, 你应该看到输出, 相当真棒, 对不对?
但是,如果我们想要在模板文件中使用变量,那会怎么样呢?简单,将index.php 文件中的模板代码更改为:
Template::view('about.html', ['title' => 'Home Page','colors' => ['red','blue','green']]);Template::view('about.html', [ 'title' => 'Home Page', 'colors' => ['red','blue','green']]);Template::view('about.html', [ 'title' => 'Home Page', 'colors' => ['red','blue','green']]);
然后,我们可以使用它如下:
{% extends layout.html %}{% block title %}{{ $title }}{% endblock %}{% block content %}<h1>Home</h1><p>Welcome to the home page, list of colors:</p><ul>{% foreach($colors as $color): %} <li>{{ $color }}</li>{% endforeach; %}</ul>{% endblock %}{% extends layout.html %} {% block title %}{{ $title }}{% endblock %} {% block content %}<h1>Home</h1><p>Welcome to the home page, list of colors:</p><ul> {% foreach($colors as $color): %} <li>{{ $color }}</li> {% endforeach; %}</ul>{% endblock %}{% extends layout.html %} {% block title %}{{ $title }}{% endblock %} {% block content %}<h1>Home</h1><p>Welcome to the home page, list of colors:</p><ul> {% foreach($colors as $color): %} <li>{{ $color }}</li> {% endforeach; %}</ul>{% endblock %}
如果我们想要确保输出安全,那该如何?替换下面的代码:
{{ $output }}{{ $output }}{{ $output }}
替换为:
{{{ $output }}}{{{ $output }}}{{{ $output }}}
这将使用 html 特别字符函数转义输出。
扩展:
{% block content %}@parent<p>Extends content block!</p>{% endblock %}{% block content %} @parent<p>Extends content block!</p>{% endblock %}{% block content %} @parent<p>Extends content block!</p>{% endblock %}
包括其他模板文件:
{% include forms.html %}{% include forms.html %}{% include forms.html %}
结论
模板引擎在大型项目中非常有用,它将使您的设计代码远离您的应用程序代码,我在我开发的自定义 MVC 框架中使用此类,发现导航到模板文件进行编辑更容易,其他人发现代码要读得更清楚。
您可以在项目中自由使用此模板类。
© 版权声明
THE END
暂无评论内容