肮脏的简单PHP模板...这可以在没有“eval”的情况下工作吗?
更新-感谢您的所有回复。这个Q有点混乱,所以如果有人感兴趣,我开始了续集。
我正在为一个朋友编写一个快速脚本,偶然发现了一种非常简单的PHP模板化方法。
基本上,这个想法是将html文档解析为heredoc字符串,因此其中的变量将由PHP扩展。
直通函数允许在字符串中进行表达式计算以及函数和静态方法调用:
function passthrough($s){return $s;}
$_="passthrough";
在heredoc字符串中解析文档的代码非常简单:
$t=file_get_contents('my_template.html');
eval("\$r=<<<_END_OF_FILE_\n$t\_END_OF_FILE_;\n");
echo $r;
唯一的问题是,它使用.eval
问题
有谁能想到一种方法来做这种模板,而不使用,但不添加解析器或大量的正则表达式疯狂?
eval
对于在不编写完整解析器的情况下转义不属于PHP变量的杂散美元符号的任何建议?杂散美元符号问题是否使这种方法对于“严肃”使用是不可行的?
下面是一些示例模板化 HTML 代码。
<script>var _lang = {$_(json_encode($lang))};</script>
<script src='/blah.js'></script>
<link href='/blah.css' type='text/css' rel='stylesheet'>
<form class="inquiry" method="post" action="process.php" onsubmit="return validate(this)">
<div class="filter">
<h2>
{$lang['T_FILTER_TITLE']}
</h2>
<a href='#{$lang['T_FILTER_ALL']}' onclick='applyFilter();'>
{$lang['T_FILTER_ALL']}
</a>
{$filter_html}
</div>
<table class="inventory" id="inventory_table">
{$table_rows}
<tr class="static"><th colspan="{$_($cols+1)}">
{$lang['T_FORM_HELP']}
</th></tr>
{$form_fields}
<tr class="static">
<td id="validation" class="send" colspan="{$cols}"> </td>
<td colspan="1" class="send"><input type="submit" value="{$lang['T_SEND']}" /></td>
</tr>
</table>
</form>
为什么使用模板?
关于在 PHP 中创建模板层是否必要,已经有一些讨论,诚然,PHP 已经非常擅长模板化了。
模板化的一些快速原因很有用:
-
您可以控制它
如果在文件转到解释器之前对其进行预处理,则可以更好地控制它。您可以注入内容,锁定权限,抓取恶意php / javascript,缓存它,通过xsl模板运行它等等。
-
良好的 MVC 设计
模板化促进视图与模型和控制器的分离。
在视图中跳入和跳出标记时,很容易变得懒惰并执行一些数据库查询或执行其他一些服务器操作。使用像上面这样的方法,每个“块”只能使用一个语句(没有分号),因此陷入该陷阱要困难得多。 具有几乎相同的好处,但是...
<?php ?>
<?= ... ?>
-
短标签并不总是启用
...我们希望我们的应用程序在各种配置上运行。
当我最初将一个概念放在一起时,它开始是一个php文件。但是在它成长之前,我不高兴,除非所有php文件在开头只有一个,在结尾只有一个,最好是所有类,除了控制器,设置,图像服务器等。<?php
?>
在我看来,我根本不想要太多的PHP,因为当 dreamweaver 或任何在床上大便时,当设计师看到这样的东西时,他们会感到困惑:
<a href="<?php $img="$img_server/$row['pic'].png"; echo $img; ?>">
<img src="<?php echo $img; ?>" /></a>
对于程序员来说,这已经足够困难了。普通的平面设计师不会去任何地方。像这样的事情更容易处理:
<a href="{$img}"><img src="{$img}" /></a>
程序员将他讨厌的代码排除在html之外,现在设计师可以发挥他的设计魔力。耶!
快速更新
考虑到每个人的建议,我认为预处理文件是要走的路,中间文件应该尽可能接近正常的“php模板化”,模板是语法糖。Eval现在仍然在我玩的时候。赫雷多克的东西已经改变了它的角色。我稍后会写更多,并试图回应一些答案,但现在......
<?php
class HereTemplate {
static $loops;
public function __construct () {
$loops=array();
}
public function passthrough ($v) { return $v; }
public function parse_markup ($markup, $no_escape=null, $vars=array()) {
extract($vars);
$eot='_EOT_'.rand(1,999999).'_EOT_';
$do='passthrough';
if (!$no_escape) $markup=preg_replace(
array(
'#{?{each.*(\$\w*).*(\$\w*).*(\$\w*).*}}?#',
'#{?{each.*(\$\w*).*(\$\w*).*}}?#',
'#{?{each}}?#',
'#{{#', '#}}#',
'#{_#', '#_}#',
),
array(
"<?php foreach (\\1 as \\2=>\\3) { ?>",
"<?php foreach (\\1 as \\2) { ?>",
"<?php } ?>",
"<?php echo <<<$eot\n{\$this->passthrough(", ")}\n$eot\n ?>",
"<?php ", " ?>",
),
$markup);
ob_start();
eval(" ?>$markup<?php ");
echo $markup;
return ob_get_clean();
}
public function parse_file ($file) {
// include $file;
return $this->parse_markup(file_get_contents($file));
}
}
// test stuff
$ht = new HereTemplate();
echo $ht->parse_file($argv[1]);
?>
...
<html>
{{each $_SERVER $key $value}
<div id="{{$key}}">
{{!print_r($value)}}
</div>
{each}}
</html>