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”.
Tags: output buffering, templates