Posts Tagged ‘templates’

Handling templates with output buffering

Monday, December 17th, 2007

I just read a blog entry by Arnold Daniels about handling templates in PHP using output buffering with a callback function.

I’ve previously used a somewhat similar approach to templating using output buffering and register_shutdown_function, but using a callback function when starting output buffering is an interesting concept I hadn’t thought of so I had to look into it.

I found his solution a little lacking, so I created my own version of it. After I had created my own version though, I read a follow-up article on the same blog with an improved version of his solution. It turned out that my version was almost identical to the version in the follow-up article (even to the point that we both implemented static methods/members which the first article didn’t do). I guess great minds really do think alike. ;)

The differences between mine and his are basically too few and unimportant to justify me blogging about it, but it’s a little late for that now.. I found his second article after doing some more research after I had started writing this post, and I might as well finish it now. I’ll be short though.

My version

  • implements the singleton pattern
  • have header and footer as separate options
  • does not implement the mark/endmark methods introduced in Daniels second version (which I’ve found no need for)

Anyway, here it is, with a very simple usage example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class OutputHandler
{
	private static $instance;
	private static $header;
	private static $footer;
	private static $templateVars = array();
	private function __construct () {}
	final private function __clone() {}
	public static function getInstance()
	{
		if (self::$instance instanceof self === false) {
			self::$instance = new self;
			$args = func_get_args();
			self::$header = (isset($args[0]) ? $args[0] : '');
			self::$footer = (isset($args[1]) ? $args[1] : '');
			ob_start(array(__CLASS__, 'callback'));
		}
		return self::$instance;
	}
	public static function callback ($buffer, $flags)
	{
		if ($flags & PHP_OUTPUT_HANDLER_END) {
			$buffer = self::parseTemplate(self::$header) . self::parseTemplate($buffer) . self::parseTemplate(self::$footer);
		}
		return $buffer;
	}
	private static function parseTemplate ($template)
	{
		return str_replace(array_keys(self::$templateVars), array_values(self::$templateVars), $template);
	}
	public static function setTemplateVar ($key, $var)
	{
		self::$templateVars[$key] = $var;
	}
}
 
OutputHandler::getInstance(file_get_contents('header.phtml'), file_get_contents('footer.phtml'));
OutputHandler::setTemplateVar('<!-- Title -->', 'Page title');
OutputHandler::setTemplateVar('<!-- The list -->', <<<ENDOUTPUT
<ul>
	<li>Item 1</li>
	<li>Item 2</li>
</ul>
ENDOUTPUT
);
 
echo '<p>Content, content, content!</p>';
echo '<p>Before the list</p>
	<!-- The list -->
	<p>After the list</p>';

When the script ends the above echo’ed lines will be output within the header and footer templates. The above echo’ed string “<!– The list –>” will be replaced with the unordered list defined with OutputHandler::setTemplateVar() and if the string “<!– Title –>” is found anywhere, including the header or footer templates, it will be replaced with “Page title”.