上一篇,我们给出了一个简单的模板引擎的例子,通过 extract
函数将变量注入到当前作用域,通过 include
将模板文件引入,从而将变量注入到了模板,但是这种方法的问题是,我们无法拿到内容,内容直接输出到了浏览器端,这篇我们看看如何拿到模板解析后的内容。
缓存区控制函数
在PHP中有一类叫 “输出控制”的方法,他们基本都以 “ob” 开头,使用 ob_start
函数将开启一个输出缓存区,所有 echo
print_r
等函数输出数据时,将会先被存储到到输出缓存区。
这个缓存区当然是一个看不到摸不着的东西,所以你可以把他想象成一个池子,所有输出函数输出的内容都会先被放到这个池子里,而不是直接输出到浏览器。
我们都知道如果一个文件中已经使用了 echo
,print_r
这些方法, 再使用header()
, setcookie()
这类需要发送heaer的函数会引起一个错误,但是当开启了输出缓存区,由于header
等函数不会受缓存区影响,echo
等方法输出的内容将被缓存到缓存区,所以下面的代码将不会再引起错误,因为 echo
等函数的内容被放到了缓存区,而不是先于 header
等函数输出内容到了浏览器,所以不会报错,下面是示例代码
<?php
ob_start();
echo "Hello\n";
setcookie("cookiename", "项羽");
ob_end_flush();
?>
通过几个ob 函数来获取模板解析后的内容
我通过 ob 函数,将要输出到浏览器的内容放到 缓存区中,然后通过 ob_get_clean
函数可以获取到缓存区的内容,并且赋值给一个变量,这样我们就拿到了模板解析后的内容
看一个例子,将以下代码保存为 demo.php
<?php
$title = "如果做一个模板引擎类" ;
$description = "简介";
ob_start();
require "tpl.php";
$output = ob_get_clean();
echo $output ;
再编写一个模板文件,将以下代码保存为 tpl.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>标题:<?php echo $title ?></h1>
<p>简介: <?php echo $description ?> </p>
</body>
</html>
将这两个文件放到你的网站目录下,通过 url 访问
可以看到,通过ob 函数我们可以将 require
进来的模板内容,赋值到一个变量 $output
上
新的模板类
我们新增了一个 fetch
方法将代码进行了简单的重构,下面是新的 view.php
的代码, 代码如下
<?php
/**
* Author: shanhuhai
* Date: 2017/7/27 19:29
* Mail: 441358019@qq.com
*/
namespace Lib;
class View
{
/**
* @var array 默认配置
*/
protected $config = [
'tplPath' => 'app/view',
];
/**
* @var array 要注入到模板中的数据
*/
protected $data = [];
/**
* 模板类的构造函数,接收一个配置数组
* View constructor.
* @param array $config
*/
public function __construct(array $config) {
$this->config = array_merge($this->config, $config);
}
/**
* 添加要注入到模板中的数据
* @param array $data 要注入的数据
*/
public function assign(array $data) {
$this->data = array_merge($this->data, $data) ;
}
/**
* 获取模渲染后的内容
* @param $tpl
* @param array $data
* @return string
* @throws \Exception
*/
public function fetch($tpl, array $data = []) {
$this->assign($data);
ob_start();
//注入变量
extract($this->data);
include $this->getTpl($tpl);
$content = ob_get_clean();
ob_end_clean();
return $content;
}
/**
* 渲染模板并输出
* @param string $tpl 模板位置
* @param array $data 要注入的数据
*/
public function display($tpl, array $data = []) {
$output = $this->fetch($tpl, $data);
echo $output;
}
/**
* 获取模板路径
* @param $tpl
* @return string
*/
private function getTpl($tpl) {
$tpl = $this->config['tplPath'].'/'.$tpl.'.php';
if(!file_exists($tpl)) {
throw new \UnexpectedValueException("视图{$tpl}不存在");
}
return $tpl;
}
}
下一篇我们将开始定义自己的模板语法,一些正则的知识是必须要的。
转载请注明:大后端 » PHP 实现自己的模板引擎(三)——加入fetch方法