Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Last active March 23, 2022 00:46
Show Gist options
  • Save xeoncross/32947f0e450212da693c to your computer and use it in GitHub Desktop.
Save xeoncross/32947f0e450212da693c to your computer and use it in GitHub Desktop.
Ultra-small template inheritance in PHP

Template Inheritance

view([filename], array $data);

Then inside [filename] you have helper functions $block(key, [default]), $start(key), and $end(). In addition, you can include a parent view using $extends = [parentview];.

Values and blocks from a child view will overwrite the values defined in a parent view (or grandparent view, etc..) allowing you to safely inherit things like a page title from multiple nested children. Suppose you view('post') and it inherited from post which in turn inherited from layout:

Layout: <?= $block('page_title', 'Welcome!'); ?>
	Page.php: <?php $page_title = 'Article Title'; ?>
		Post.php <?php $page_title = $post->title; ?>

The result would be $post->title and not "Article Title" or "Welcome!" dispite the fact they were defined in the parent views.

<?php $start('nav'); ?>
ONE-NAV
<?php $end(); ?>
<?php $one = 'one'; ?>
<?php $shared = 'one'; ?>
One Content
<?php $extends = 'two'; ?>
// view('one') renders:
ONE-NAV
1. one
2. two
3. one
Three Content
<?= $block('nav', 'THREE-NAV'); ?>
1. <?= $block('one'); ?>
2. <?= $block('two'); ?>
3. <?= $block('shared'); ?>
Three Content
<?php $start('nav'); ?>
TWO-NAV
<?php $end(); ?>
<?php $one = 'two'; ?>
<?php $two = 'two'; ?>
<?php $shared = 'two'; ?>
Two Content
<?php $extends = 'three'; ?>
<?php
/**
* This looks like a mess, and it is, but it's a powerful mess.
* Auto-scoped $block('name') and template inheritance.
*
* "foo.php" child view:
*
* <?php $title = 'SEO Title'; ?>
* <?php $nav = view('nav', array('links'=> $links_array))); ?>
* This is the content of foo.php
* <?php $extends = 'layout'; ?>
*
* "nav.php" view:
*
* <ul>
* <?php foreach($links as $a => $link): ?>
* <li><a href="<?= $a; ?>"><?= $link; ?></a></li>
* <?php endif; ?>
* </ul>
*
* Then inside 'layout.php':
*
* <?= $block('nav', '<ul>...</ul>'); ?>
* <h1><?= $block('title', 'Hello World'); ?></h1>
* <?= $block('content'); ?>
* &copy; 2014 Company
*/
function view($file, $data = array())
{
$__scope = $data;
unset($data);
$extends = $file;
while(isset($extends)) {
$__file = $extends;
unset($extends, $content);
$__v = $__scope = $__scope + array_diff_key(get_defined_vars(), array('__file'=>0, '__scope'=>0));
$start = function($name) use(&$__v) {
ob_start(function($buffer) use(&$name, &$__v) {
if(empty($__v[$name])) {
$__v[$name] = $buffer;
}
return $__v[$name];
});
};
$end = function() {
ob_end_flush();
};
$block = function($key, $default = null) use(&$__v) {
return isset($__v[$key]) ? $__v[$key] : $default;
};
ob_start();
require("theme/$__file.php");
$content = trim(ob_get_contents());
extract($__v, EXTR_SKIP);
// $content is a funny variable (keep the original unless this is the last parent)
if(isset($__v['content'])) {
if(empty($__scope['content'])) {
$__scope['content'] = $__v['content'];
}
}
unset($__v, $__file, $block, $start, $end);
ob_end_clean();
}
return $content;
}
@onebitrocket
Copy link

onebitrocket commented Dec 12, 2017

As much as I've tried, I cannot nest a partial and pass additional data to is, such as on line 10 of view.php .

<?php $nav = view('nav', array('links'=> $links_array))); ?>

Does the passed data need to be in a set array format?

In my case there is a variable $settings set on the index page.

This is passed to the view function,

echo view('home', $settings);

The home.php template file references the passed $settings variable, but then nothing happens

<?php
  $nav = view('partials/nav', array('links' => $settings['menu']));
?>

I created a small test project, adding an index file, that calls the view function.
https://github.com/onebitrocket/php-ti

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment