代码之家  ›  专栏  ›  技术社区  ›  matte

如何建模模板类

  •  0
  • matte  · 技术社区  · 15 年前

    我正在为自己的项目编写一个基本模板类。基本用法如下:

    $template = new Template('template_file.php');
    $template->assignVariable('pageTitle', 'Home page');
    $template->render();
    

    “template_file.php”的内容:

    <?php print $pageTitle; ?>
    

    这是模板类逐步执行的操作:

    1. 调用assignvariable方法时将变量存储在私有数组中
    2. 调用render方法时,提取存储变量,并在 ob_start() ob_end_clean() 阻止。将输出存储在变量中 ob_get_contents() 然后打印存储的输出。

    我知道这是一个非常简单的模板化类,但工作正常。问题是我应该将包含模板文件委托给另一个类吗?我在为这门课编写单元测试时有个问题。我认为应该封装文件系统交互。你怎么认为?如果您认为不应该这样做,那么如何在我的测试中模拟包含一个文件呢?

    也许我只是将模板文件的内容传递给类,如下所示:

    $templateContent = file_get_contents('template_file.php');
    $template = new Template($templateContent);
    ...
    

    编辑:为了编写更好的单元测试和封装,我决定封装模板类的输入过程。但正如约翰内斯指出的,我需要 eval() 为了这个目的,这似乎是不正确的。Johannes向我指出了流包装器的方向,因为它模拟了包括在单元测试中的内容。但这给了我一个新的想法。这是我要做的,我将继续使用 include() 在我的模板类中,但这次是使用流包装器。初始化模板类时,我将把协议处理程序传递给它。通过这种方式,我可以创建自己的流包装器,用于从数据库获取模板数据或使用局部变量。以下是示例:

    $template = new Template('file://template_file.php');
    
    stream_wrapper_register('database', 'My_Database_Stream');
    $template = new Template('database://templates/3'); // templates table, row id 3
    
    stream_wrapper_register('var', 'My_Var_Stream');
    $myTemplate = '<?php print "Hello world!"; ?>';
    $template = new Template('var://myTemplate');
    

    我已经为局部变量实现了自定义流包装器。这里是:

    class My_Var
    {
        protected $position;
        protected $variable;
        function stream_open($path, $mode, $options, &$openedPath) {
            $url = parse_url($path);
            global $$url['host'];
            $this->variable = $$url['host'];
            $this->position = 0;
    
            return true;
        }
        public function stream_read($count) {
            $ret = substr($this->variable, $this->position, $count);
            $this->position = strlen($ret);
            return $ret;
        }
        public function stream_eof() {
            return $this->position >= strlen($this->variable);
        }
    }
    
    
    stream_wrapper_register('var', 'My_Var');
    $myvar = '<?php print "mert"; ?>';
    include 'var://myvar';
    exit;
    
    4 回复  |  直到 15 年前
        1
  •  0
  •   johannes    15 年前

    通过使用file_get_contents()传递内容,您必须使用eval()来执行,这在很多方面都很糟糕。这里最相关的一个问题是操作码缓存无法缓存文件。执行include(“template_file.php”);让我们 APC 或者其他人缓存已编译的脚本。

        2
  •  1
  •   dwergkees    15 年前

    我一直喜欢这个家伙的方法:

    http://www.massassi.com/php/articles/template_engines/

    这种方法利用了PHP作为模板引擎启动的事实。(作者还注意到,用PHP编写一个膨胀的模板引擎是愚蠢的,而实际上它本身就是一个模板引擎。)它可能不会直接回答您的问题,但可能会帮助您。

        3
  •  0
  •   John Parker    15 年前

    不管eval与使用include的坏处如何,要回答您的问题,我必须同意并使用一个单独的类来封装解决方案的I/O方面。

    虽然这看起来像是过度杀戮(在大多数情况下都是这样),但这可能是提供隔离您所追求的控制/依赖注入的唯一明智方法。

        4
  •  0
  •   just somebody    15 年前

    问题是我应该将包含模板文件委托给另一个类吗?

    问题是,为什么不呢?