我正在使用PHP类导出模板,并且有一个用于调用函数的标记,应该从插件脚本动态加载。脚本存储在目录中,并以标记中函数的名称命名。然后将动态加载的函数名称存储在一个数组中,这样它们只被加载一次。这样做很好,所以我的问题不是如何解决这个问题,而是我要求输入是否这是一个稳定安全的解决方案,如果有更好的方法来解决这个问题,或者我已经监督了什么?
Observer和Decorator模式都不适用于此设计,我希望它保持简约;在这种特殊情况下,我不会使用类,只使用函数。此外,如果您认为这是一个有效的解决方案,或者您提出了更好的建议;我可能也会在其他类似的类中实现它 - 因此我想从头开始做到这一点。所以,请严格和批评。
该课程看起来像这样:
<?php
// TemplateEngine.php
class TemplateEngine {
private static $functions = array();
private $vars = array();
...
public function &getVars() { return $this->vars; }
...
private function call(&$tag) {
$name = strtr(strtolower($tag->id),'-','_');
$value = $tag->value;
$func = false;
if(preg_match('/^[\w\_]+$/',$name)) {
if(isset(self::$functions[$name])) {
$func = &self::$functions[$name];
} else {
$script = __DIR__.'/functions/'.$name.'.php';
if(file_exists($script)) $func = require_once $script;
self::$functions[$key] = &$func;
}
}
$ret = '';
if(is_callable($func)) $ret = $func($this,$value);
return $ret;
}
...
}
然后函数脚本迭代一个数组并用它的值解析一个字符串,如下所示:
<?php
// functions/iterate.php
return function(&$templ,$param) {
$vars = &$templ->getVars();
list($key,$value) = $param;
if(!isset($vars[$key])) return '';
$var = $vars[$key];
if(!is_array($var)) $var = array($key=>$var);
$value = stripcslashes($value);
$ret = '';
foreach($var as $k=>$v) {
$vars['key'] = $k;
$vars['value'] = $v;
$ret .= $templ->parse($value);
}
return $ret;
}
在模板中,标签可能如下所示:
{call iterate|js-files|<script src="{value}">\n}
这样的标签将调用函数“iterate”并在模板变量数组中查找索引“js-files”(从配置文件中读取),并解析字符串“&lt; script ...&gt ;”
答案 0 :(得分:1)
一种方法(就像我在my template engine for PHP, Contemplate中所做的那样)是这样的:
在PHP模板类中有一个存储插件函数(及其名称)的数组,然后使用php __call
magic method调用用户定义的插件(使用call_user_func)如果它是一个名字你的插件表中的函数,否则调用被调用的方法(因为它将是一个本机方法)
注意::这有点慢(在委托时使用__call
),但这是PHP(5.1 +)中动态方法的最佳解决方案
用户可以在模板引擎中添加插件(例如):
public function addPlugin($name, $handler)
{
$this->plugins[$name] = $handler;
}
使用示例:
MyTemplateEngine->addPlugin('foo', function(){ return 'foo'; });
调用插件:
MyTemplateEngine->foo();