PHP 中带有 {{field}} 的简单模板系统
Simple templating system with {{field}} in PHP
我正在为 PHP 中的 CMS 设计一个简单的模板系统,该系统目前在内部使用类似的东西:
require_once 'templates/template1.php`;
导入所需的模板。
我希望此 PHP 文件中的每个内容 {{field123}}
在传递到 require_once
并由 PHP 执行之前自动转换为 <?php echo $row['field123']; ?>
.
有没有办法激活 预处理器(我知道 PHP 已经以预处理器命名)做这个替换 {{anything}} -> <?php echo $row['anything']; ?>
在执行 PHP 代码之前 template1.php
?如果不是,通常的做法是什么?
如评论和 How do I capture PHP output into a variable? 中所述,使用输出缓冲可以工作:
<?php
ob_start();
?>
Hello
{{field123}} and {{field4}}
World
<?php // or require_once 'template1.php'; ?>
<?php
$s = ob_get_clean();
$a = array('field123' => 'test', 'field4' => 'test2');
$s = preg_replace_callback('/{{(.*?)}}/', function ($m) use ($a) { return isset($a[$m[1]]) ? $a[$m[1]] : $m[0]; }, $s);
echo $s;
?>
// Output:
// Hello
// test and test2
// World
这里我们也用了类似的方法来做替换
在模板中包含 PHP 代码 - 特别是具有潜力 side-effects 的代码 - 会很快变脏。我建议使用静态模板,将它们视为字符串而不是执行它们,然后将它们解析为标记,由您的主应用程序编译它们并处理输出。
这是一个基本的实现,它可以将变量解析为标记,还可以处理模板中映射的函数调用。首先,“获取”我们的模板(举个简单的例子):
$tpl = 'This is a sample template file.
It can have values like {{foo}} and {{bar}}.
It can also invoke mapped functions:
{{func:hello}} or {{func:world}}.
Hello user {{username}}. Have a good day!';
然后,模板解析器:
function parse_template(string $tpl, array $vars): string {
// Catch function tokens, handle if handler exists:
$tpl = preg_replace_callback('~{{func:([a-z_]+)}}~', function($match) {
$func = 'handler_' . $match[1];
if(function_exists($func)) {
return $func();
}
return "!!!What is: {$match[1]}!!!";
}, $tpl);
// Generate tokens for your variable keys;
$keys = array_map(fn($key) => '{{' . $key . '}}', array_keys($vars));
// Substitute tokens:
$tpl = str_replace($keys, $vars, $tpl);
return $tpl;
}
这些是我们的处理函数,handler_X
匹配 {{func:X}}
。
function handler_hello() {
return 'HELLO THERE';
}
function handler_world() {
return '@Current World Population: ' . mt_rand();
}
那么,这里是你想要解析的变量:
$vars = [
'foo' => 'Food',
'bar' => 'Barnacle',
'username' => 'Herbert'
];
现在让我们解析我们的模板:
$parsed = parse_template($tpl, $vars);
echo $parsed;
这导致:
This is a sample template file.
It can have values like Food and Barnacle.
It can also invoke mapped functions:
HELLO THERE or @Current World Population: 1477098027.
Hello user Herbert. Have a good day!
工作完成。你真的不需要一个复杂的模板引擎来做这样的事情。您可以轻松地扩展它以允许处理程序接收在模板标记中定义的参数——但是我将把它留给您的作业部分。这应该用来证明这个概念。
我正在为 PHP 中的 CMS 设计一个简单的模板系统,该系统目前在内部使用类似的东西:
require_once 'templates/template1.php`;
导入所需的模板。
我希望此 PHP 文件中的每个内容 {{field123}}
在传递到 require_once
并由 PHP 执行之前自动转换为 <?php echo $row['field123']; ?>
.
有没有办法激活 预处理器(我知道 PHP 已经以预处理器命名)做这个替换 {{anything}} -> <?php echo $row['anything']; ?>
在执行 PHP 代码之前 template1.php
?如果不是,通常的做法是什么?
如评论和 How do I capture PHP output into a variable? 中所述,使用输出缓冲可以工作:
<?php
ob_start();
?>
Hello
{{field123}} and {{field4}}
World
<?php // or require_once 'template1.php'; ?>
<?php
$s = ob_get_clean();
$a = array('field123' => 'test', 'field4' => 'test2');
$s = preg_replace_callback('/{{(.*?)}}/', function ($m) use ($a) { return isset($a[$m[1]]) ? $a[$m[1]] : $m[0]; }, $s);
echo $s;
?>
// Output:
// Hello
// test and test2
// World
这里我们也用了类似
在模板中包含 PHP 代码 - 特别是具有潜力 side-effects 的代码 - 会很快变脏。我建议使用静态模板,将它们视为字符串而不是执行它们,然后将它们解析为标记,由您的主应用程序编译它们并处理输出。
这是一个基本的实现,它可以将变量解析为标记,还可以处理模板中映射的函数调用。首先,“获取”我们的模板(举个简单的例子):
$tpl = 'This is a sample template file.
It can have values like {{foo}} and {{bar}}.
It can also invoke mapped functions:
{{func:hello}} or {{func:world}}.
Hello user {{username}}. Have a good day!';
然后,模板解析器:
function parse_template(string $tpl, array $vars): string {
// Catch function tokens, handle if handler exists:
$tpl = preg_replace_callback('~{{func:([a-z_]+)}}~', function($match) {
$func = 'handler_' . $match[1];
if(function_exists($func)) {
return $func();
}
return "!!!What is: {$match[1]}!!!";
}, $tpl);
// Generate tokens for your variable keys;
$keys = array_map(fn($key) => '{{' . $key . '}}', array_keys($vars));
// Substitute tokens:
$tpl = str_replace($keys, $vars, $tpl);
return $tpl;
}
这些是我们的处理函数,handler_X
匹配 {{func:X}}
。
function handler_hello() {
return 'HELLO THERE';
}
function handler_world() {
return '@Current World Population: ' . mt_rand();
}
那么,这里是你想要解析的变量:
$vars = [
'foo' => 'Food',
'bar' => 'Barnacle',
'username' => 'Herbert'
];
现在让我们解析我们的模板:
$parsed = parse_template($tpl, $vars);
echo $parsed;
这导致:
This is a sample template file.
It can have values like Food and Barnacle.
It can also invoke mapped functions:
HELLO THERE or @Current World Population: 1477098027.
Hello user Herbert. Have a good day!
工作完成。你真的不需要一个复杂的模板引擎来做这样的事情。您可以轻松地扩展它以允许处理程序接收在模板标记中定义的参数——但是我将把它留给您的作业部分。这应该用来证明这个概念。