如何建模模板类

时间:2010-01-17 13:10:58

标签: php unit-testing

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

$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()的变量中,然后打印存储的输出。
  3. 我知道这是一个非常简单的模板类,但按预期工作。问题是我应该将包含模板文件委托给另一个类吗?我在为这堂课写单元测试时遇到了这个问题。我认为应该封装文件系统交互。你怎么看?如果您认为它不应该,我怎么能在我的测试中模拟包含文件?

    也许我只是将模板文件的内容传递给类:

    $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 个答案:

答案 0 :(得分:1)

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

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

这种方法利用了PHP作为模板引擎启动的事实。 (作者还指出,在PHP中编写一个臃肿的模板引擎是愚蠢的,因为它实际上本身就是一个模板引擎。)它可能不会直接回答你的问题,但它可能对你有帮助。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

无论eval与使用include的恶意如何,回答你的问题,我都必须同意并使用一个单独的类来封装解决方案的I / O方面。

虽然这看起来有点矫枉过正(在大多数情况下都是如此),但这可能是提供隔离控制/依赖注入的唯一理智方式。

答案 3 :(得分:0)

  

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

问题是,为什么不呢?