我正在为自己的项目编写一个基本的模板类。基本用法是:
$template = new Template('template_file.php');
$template->assignVariable('pageTitle', 'Home page');
$template->render();
'template_file.php'的内容:
<?php print $pageTitle; ?>
这是模板类一步一步做的事情:
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;
答案 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)
问题是我应该将包含模板文件委托给另一个类吗?
问题是,为什么不呢?