修改加载自定义标签库的方式

This commit is contained in:
TOP糯米 2019-07-28 16:06:38 +08:00
parent b4d226517f
commit a2e2602c59
5 changed files with 194 additions and 193 deletions

View File

@ -6,14 +6,14 @@
</head>
<body>
<?php foreach ($array as $vo): echo $vo; endforeach; ?>
<?php foreach ($array as $vo): echo ($vo); endforeach; ?>
将上面的内容放入raw标签
<volist name="array" id="vo">
{$vo}
</volist>
<?php if ($var == 1): echo time(); endif; ?>
<?php echo ($a); if ($var == 1): echo (time()); if ($var1 == 2): echo (time()); endif; endif; ?>
扩展的标签:
<?php echo 'Hello'; ?>

View File

@ -12,8 +12,12 @@
{$vo}
</volist>
</raw>
{$a}
<if condition="$var == 1">
{:time()}
<if condition="$var1 == 2">
{:time()}
</if>
</if>
扩展的标签:
<say what="Hello" />

View File

@ -3,24 +3,15 @@ require 'template/Engine.php';
require 'template/Extend.php';
$content = file_get_contents('./demo/index.html');
echo "\r\n\r\n原始内容\r\n\r\n";
print_r($content);
$template = new \template\Engine();
// 默认编译结果
$t1 = microtime(true);
$template = \template\Engine::instance();
// 加载自定义标签库
$template->loadTaglib(\template\Extend::class);
// 编译
$result = $template->compile($content);
echo "\r\n\r\n第一次结果\r\n\r\n";
print_r($result);
// 开始处理用户定义标签库
$extend = new \template\Extend();
$result = $extend->parseCustomizeTags($result);
// 用户定义标签库处理结束
// 最后还原raw标签
$result = $template->returnRaw($result);
$t2 = microtime(true);
echo '执行时间' . ($t2 - $t1) . "\r\n";
echo "\r\n\r\n第二次结果\r\n\r\n";
print_r($result);
file_put_contents(md5(time()) . '.php', $result);

View File

@ -9,6 +9,12 @@ namespace template;
*/
class Engine
{
/**
* @var null 单一实例
*/
private static $instance = null;
/**
* @var string 左定界符
*/
@ -30,21 +36,24 @@ class Engine
protected $config = null;
/**
* @var null 模板路径
* @var null 扩展标签库
*/
private $viewDir = null;
private $extend = [];
/**
* @var array 扩展标签库类实例
*/
private $extendInstance = [];
/**
* @var array 默认标签定义
*/
private $defaultTags = [
'php' => ['attr' => null, 'close' => 1],
'if' => ['attr' => 'condition', 'close' => 1],
'else' => ['attr' => 'condition', 'close' => 0],
'volist' => ['attr' => 'name,id,key', 'close' => 1],
'assign' => ['attr' => 'name,value', 'close' => 0],
'switch' => ['attr' => 'name', 'close' => 1],
'case' => ['attr' => 'value', 'close' => 1],
'default' => ['attr' => '', 'close' => 1]
'assign' => ['attr' => 'name,value', 'close' => 0]
];
/**
@ -52,24 +61,44 @@ class Engine
* Engine constructor.
* @throws \Exception
*/
public function __construct()
private function __construct()
{
// 仅作示例,请在外部传入模板目录
$this->viewDir = './demo/';
// $this->config = Register::get('Config')->get('view');
$this->config['dir'] = './demo/';
if (isset($this->config['left']) && $this->config['left']) {
$this->left = $this->config['left'];
}
if (isset($this->config['right']) && $this->config['right']) {
$this->right = $this->config['right'];
}
}
/**
* 获取类单一实例
* @return null|Engine
*/
public static function instance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 处理模板继承
* @param $template
* @return mixed
*/
private function parseExtend($tmpl)
private function parseExtend($template)
{
$pattern = '#' . $this->left . 'extend +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
preg_match($pattern, $tmpl, $matches);
preg_match($pattern, $template, $matches);
if (!empty($matches)) {
$blockPattern = '#' . $this->left . 'block +name=[\'"](.*?)[\'"]' . $this->right;
$blockPattern .= '([\s\S]*?)' . $this->left . '\/block' . $this->right . '#';
// 获得被继承的模板内容
$file = $this->viewDir . $matches[1] . '.html';
$file = $this->config['dir'] . $matches[1] . '.html';
$extendFileContent = null;
if (file_exists($file)) {
$extendFileContent = file_get_contents($file);
@ -80,7 +109,7 @@ class Engine
// 被继承模板中的块
preg_match_all($blockPattern, $extendFileContent, $extendResult);
// 继承模板中的块
preg_match_all($blockPattern, $tmpl, $templateResult);
preg_match_all($blockPattern, $template, $templateResult);
// 组合搜索的块数组
$search = [];
$defaultContent = [];
@ -104,172 +133,219 @@ class Engine
$replaceArray[] = $defaultContent[$key];
}
}
$tmpl = str_replace($searchArray, $replaceArray, $extendFileContent);
$template = str_replace($searchArray, $replaceArray, $extendFileContent);
}
return $tmpl;
return $template;
}
/**
* 处理include标签
* @return bool
* @param $template
* @return null|string|string[]
*/
private function parseInclude($tmpl)
private function parseInclude($template)
{
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
$tmpl = preg_replace_callback($pattern, function ($result) {
$template = preg_replace_callback($pattern, function ($result) {
$str = null;
$file = $this->viewDir . $result[1] . '.html';
$file = $this->config['dir'] . $result[1] . '.html';
if (file_exists($file)) {
$str = file_get_contents($file);
}
return $str;
}, $tmpl);
}, $template);
// 处理多层include
if ($this->hasInclude($tmpl)) {
$tmpl = $this->parseInclude($tmpl);
if ($this->hasInclude($template)) {
$template = $this->parseInclude($template);
}
return $tmpl;
return $template;
}
/**
* 检测是否含有include
* @param $tmpl
* @param $template
* @return bool
*/
private function hasInclude($tmpl)
private function hasInclude($template)
{
$pattern = '#' . $this->left . 'include +file=[\'"](.*?)[\'"] +/' . $this->right . '#';
preg_match($pattern, $tmpl, $matches);
preg_match($pattern, $template, $matches);
return !empty($matches);
}
/**
* 分析参数以及函数输出
* @param $template
* @return mixed
*/
private function parseVars($tmpl)
private function parseVars($template)
{
preg_match_all('#{(.*?)}#', $tmpl, $matches);
preg_match_all('#{(.*?)}#', $template, $matches);
$search = [];
$replace = [];
for ($i = 0; $i < count($matches[0]); $i++) {
$start = substr($matches[1][$i], 0, 1);
$search[] = $matches[0][$i];
if ($start == '$') {
$search[] = $matches[0][$i];
$replace[] = '<?php echo ' . $matches[1][$i] . '; ?>';
$replace[] = '<?php echo (' . $matches[1][$i] . '); ?>';
} elseif ($start == ':') {
$search[] = $matches[0][$i];
$replace[] = '<?php echo ' . ltrim($matches[1][$i], ':') . '; ?>';
$replace[] = '<?php echo (' . ltrim($matches[1][$i], ':') . '); ?>';
} else {
$replace[] = $matches[0][$i];
}
}
$tmpl = str_replace($search, $replace, $tmpl);
return $tmpl;
$template = str_replace($search, $replace, $template);
return $template;
}
/**
* 处理用户自定义标签
* @param $tmpl
* @return null|string|string[]
* 外部加载扩展标签
* @param $lib
*/
public function parseCustomizeTags($tmpl)
public function loadTaglib($lib)
{
return $this->parseTags($tmpl, $this->tags);
$this->extend[] = $lib;
}
/**
* 处理默认的标签
* @param $tmpl
* 标签处理
* @param $template
* @return null|string|string[]
*/
private function parseDefaultTags($tmpl)
private function parseTags($template)
{
return $this->parseTags($tmpl, $this->defaultTags);
foreach ($this->extend as $lib) {
$this->extendInstance[$lib] = $object = new $lib;
foreach ($object->tags as $name => $tag) {
if (!isset($this->tags[$name]) && !isset($this->defaultTags[$name])) {
$this->tags[$name] = $tag;
}
}
}
$tags = array_merge($this->defaultTags, $this->tags);
return $this->_parseTags($template, $tags);
}
/**
* 获取标签处理结果
* @param $name
* @param $tagContent
* @return mixed
*/
private function getTagParseResult($name, $tagContent = [])
{
if (method_exists($this, $name)) {
return $this->{$name}($tagContent);
} else {
foreach ($this->extendInstance as $item) {
if (method_exists($item, $name)) {
return $item->{$name}($tagContent);
}
}
return null;
}
}
/**
* 进行标签处理
* @param $tmpl
* @param $template
* @param $tags
* @return null|string|string[]
*/
private function parseTags($tmpl, $tags)
private function _parseTags($template, $tags)
{
foreach ($tags as $name => $item) {
$attr = ($item['attr']) ? ' +(.*?)' : null;
$pattern = '#' . $this->left . $name . $attr . ($item['close'] ? $this->right : '\/' . $this->right . '#');
if ($item['close']) {
$pattern .= '([\s\S]*?)' . $this->left . '\/' . $name . $this->right . '#';
}
preg_match_all($pattern, $tmpl, $matches);
$pattern = '#' . $this->left . $name . '(.*?)' . ($item['close'] ? null : '\/') . $this->right . '#';
preg_match_all($pattern, $template, $matches);
for ($i = 0; $i < count($matches[0]); $i++) {
$attrPattern = '#(.*?)=[\'"](.*?)[\'"]#';
preg_match_all($attrPattern, $matches[1][$i], $result);
$tag = [];
if (!empty($result)) {
foreach ($result[1] as $key => $value) {
$tag[trim($value, ' ')] = $result[2][$key];
if ($item['attr']) {
$attrPattern = '#(.*?)=[\'"](.*?)[\'"]#';
preg_match_all($attrPattern, $matches[1][$i], $result);
if (isset($result[0]) && !empty($result[0])) {
foreach ($result[1] as $key => $value) {
$tag[trim($value, ' ')] = $result[2][$key];
}
}
}
if ($item['close']) {
$tagContent = isset($matches[2][$i]) ? $matches[2][$i] : (($attr) ? null : $matches[1][$i]);
$content = $this->{'_' . $name . '_start'}($tag, $tagContent);
if ($item['close']) {
$content .= $this->{'_' . $name . '_end'}($tag, $tagContent);
}
} else {
$content = $this->{'_' . $name . '_start'}($tag);
}
$tmpl = str_replace($matches[0][$i], $content, $tmpl);
$function = ($item['close']) ? '_' . $name . '_start' : '_' . $name;
$template = str_replace($matches[0][$i], $this->getTagParseResult($function, $tag), $template);
}
if ($item['close']) {
$closePattern = '#' . $this->left . '\/' . $name . $this->right . '#';
$template = preg_replace_callback($closePattern, function () use ($name) {
$function = '_' . $name . '_end';
return $this->getTagParseResult($function);
}, $template);
}
}
return preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $tmpl);
return preg_replace('#\?>([\r|\n|\s]*?)<\?php#', '', $template);
}
/**
* 处理raw标签
* @param $tmpl
* @param $template
* @return null|string|string[]
*/
private function parseRaw($tmpl)
private function parseRaw($template)
{
$pattern = '#' . $this->left . 'raw' . $this->right . '([\s\S]*?)';
$pattern .= $this->left . '\/raw' . $this->right . '#';
$tmpl = preg_replace_callback($pattern, function ($matches) {
$template = preg_replace_callback($pattern, function ($matches) {
return str_replace([
$this->left, $this->right,
'{', '}'
], [
'<raw!--', '--raw>',
'{raw!--', '--raw}'
'<-raw!--', '--raw->'
], $matches[1]);
}, $tmpl);
return $tmpl;
}, $template);
return $template;
}
/**
* 还原raw
* @param $tmpl
* @return null|string|string[]
* @param $template
* @return mixed
*/
public function returnRaw($tmpl)
public function returnRaw($template)
{
$pattern = '#[{|<]raw!--([\s\S]*?)--raw[>|}]#';
$tmpl = preg_replace_callback($pattern, function ($matches) {
$left = substr($matches[0], 0, 1);
$right = substr($matches[0], -1);
return $left . $matches[1] . $right;
}, $tmpl);
return $tmpl;
$template = str_replace([
'<raw!--', '--raw>',
'<-raw!--', '--raw->'
], [
$this->left, $this->right,
'{', '}'
], $template);
return $template;
}
/**
* php标签开始
* @return string
*/
private function _php_start()
{
return '<?php ';
}
/**
* php标签结束
* @return string
*/
private function _php_end()
{
return ' ?>';
}
/**
* if标签
* @param $tag
* @param $content
* @return string
*/
private function _if_start($tag, $content)
private function _if_start($tag)
{
return '<?php if (' . $tag['condition'] . '): ?>' . $content;
return '<?php if (' . $tag['condition'] . '): ?>';
}
/**
@ -299,10 +375,9 @@ class Engine
/**
* volist标签
* @param $tag
* @param $content
* @return string
*/
private function _volist_start($tag, $content)
private function _volist_start($tag)
{
if (substr($tag['name'], 0, 1) == ':') {
$name = substr($tag['name'], 1);
@ -311,7 +386,7 @@ class Engine
}
$key = (empty($tag['key'])) ? null : '$' . $tag['key'] . ' = 0;';
$parse = '<?php ' . $key . ' foreach (' . $name . ' as $' . $tag['id'] . '): ';
$parse .= ($key ? '$' . $tag['key'] . '++;' : null) . ' ?>' . $content;
$parse .= ($key ? '$' . $tag['key'] . '++;' : null) . ' ?>';
return $parse;
}
@ -329,99 +404,30 @@ class Engine
* @param $tag
* @return string
*/
private function _assign_start($tag)
private function _assign($tag)
{
return '<?php $' . $tag['name'] . ' = ' . $tag['value'] . '; ?>';
}
/**
* switch标签
* @param $tag
* @param $content
* @return string
*/
private function _switch_start($tag, $content)
{
$parse = '<?php switch($' . $tag['name'] . '): ?>' . $content;
return $parse;
}
/**
* switch标签结束
* @return string
*/
private function _switch_end()
{
$parse = '<?php endswitch; ?>';
return $parse;
}
/**
* case标签
* @param $tag
* @param $content
* @return string
*/
private function _case_start($tag, $content)
{
if (is_numeric($tag['value'])) {
$caseVar = $tag['value'];
} else {
$caseVar = '\'' . $tag['value'] . '\'';
}
$parse = '<?php case ' . $caseVar . ': ?>' . $content;
return $parse;
}
/**
* case标签结束
* @return string
*/
private function _case_end()
{
$parse = '<?php break; ?>';
return $parse;
}
/**
* default标签
* @param $tag
* @param $content
* @return string
*/
private function _default_start($tag, $content)
{
$parse = '<?php default: ?>' . $content;
return $parse;
}
/**
* default标签结束
* @return string
*/
private function _default_end()
{
$parse = '<?php break; ?>';
return $parse;
}
/**
* 获取编译后的内容
* @param $tmpl
* @param $template
* @return bool|mixed|null|string|string[]
*/
public function compile($tmpl)
public function compile($template)
{
$tmpl = $this->parseRaw($tmpl);
// 处理raw标签
$template = $this->parseRaw($template);
// 处理模板继承标签
$tmpl = $this->parseExtend($tmpl);
$template = $this->parseExtend($template);
// 处理include标签
$tmpl = $this->parseInclude($tmpl);
$template = $this->parseInclude($template);
// 处理变量以及函数
$tmpl = $this->parseVars($tmpl);
$template = $this->parseVars($template);
// 处理定义的标签
$tmpl = $this->parseDefaultTags($tmpl);
return $tmpl;
$template = $this->parseTags($template);
return $template;
}
}

View File

@ -2,13 +2,13 @@
namespace template;
class Extend extends Engine
class Extend
{
protected $tags = [
public $tags = [
'say' => ['attr' => 'what', 'close' => 0]
];
protected function _say_start($tag)
public function _say($tag)
{
return '<?php echo \''. $tag['what'] .'\'; ?>';
}