动态添加函数到 PHP class 作为插件

Dynamically add functions to PHP class as plugins

我正在使用 PHP class 导出模板,并且有一个用于调用函数的标记,该标记应从插件脚本中动态加载。脚本存储在一个目录中,并以标签中函数的名称命名。动态加载函数的名称然后存储在一个数组中,因此它们只加载一次。这工作正常,所以我的问题不是如何解决这个问题,而是我会询问是否这是一个稳定和安全的解决方案,是否有更好的方法来解决这个问题,或者我已经监督过的事情?

Observer nor the Decorator 模式都不适合这种设计,我希望它保持简约;在这种特殊情况下,我不会使用 classes,只会使用函数。另外,如果您认为这是一个可行的解决方案,或者您有更好的建议;我可能也会在其他类似的 classes 中实现它 - 因此我想从一开始就把它做好。所以,请严格批评。

class 看起来像这样:

<?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",然后解析字符串 "