Skip to content

Instantly share code, notes, and snippets.

@CHH
Created August 2, 2011 21:09
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save CHH/1121233 to your computer and use it in GitHub Desktop.
Save CHH/1121233 to your computer and use it in GitHub Desktop.
PHP Templating Engine with bindable $this support in 53 LOC
vendor/
composer.lock

Template Class, with support for binding object contexts to the template.

Requires PHP 5.4 for Closure $this support

Install:

Put this in a file named composer.json:

{
    "repositories": [
        {"type": "vcs", "url": "git://gist.github.com/1121233.git"}
    ],
    "require": {
        "chh/simple-template": "*"
    }
}

Get Composer and install:

wget http://getcomposer.org/composer.phar
php composer.phar install

Usage:

hello_world.phtml

Hello World <?= $name ?>
Here is the output of some method: <?= $this->foo() ?>
Here is the value of a context property: <?= $this->bar ?>

Template Controller

<?php

require "Template.php";

use CHH\Template;

class Context
{
  var $bar = "Some Context Property";

  function foo()
  {
    return "Context::foo()";
  }
}

$template = new Template('/hello_world.phtml');
echo $template->render(new Context, ['name' => 'Jim']);

This yields:

Hello World Jim
Here is the output of some method: Context::foo()
Here is the value of a context property: Some Context Property
{
"name": "chh/simple-template",
"description": "Minimal template class, using Closure Object Binding.",
"authors": [
{ "name": "Christoph Hochstrasser", "email": "christoph.hochstrasser@gmail.com" }
],
"require": {
"php": ">=5.4.0"
},
"autoload": {
"classmap": ["."]
}
}
<?php
namespace CHH;
class SimpleTemplate
{
protected $file;
function __construct($file)
{
if (!is_file($file) or !is_readable($file)) {
throw new \InvalidArgumentException(
"File $file does not exist or is not readable"
);
}
$this->file = $file;
}
# Renders the template
#
# context - Is the object to which $this inside
# the template refers to.
# vars - Is an array of key-value pairs, which are
# available within the template as local variables.
#
# Returns the rendered template as String.
function render($context = null, array $locals = [])
{
if (null === $context) {
$context = new \StdClass;
} else if (is_object($context)) {
$context = clone $context;
} else {
throw new \InvalidArgumentException("Invalid Context given. Context must be an object");
}
# Create the sandbox for the template to execute in
$template = function($__file__, array $__locals__ = array()) {
// Set all keys in $__locals__ as local variables
foreach ((array) $__locals__ as $var => $value) {
$$var = $value;
}
unset($var, $value, $__locals__);
ob_start();
include $__file__;
return ob_get_clean();
};
# Bind $this inside the closure to the context object
$template = $template->bindTo($context);
return $template($this->file, $locals);
}
}
@saltybeagle
Copy link

Any thoughts on how you prevent views from accessing the private vars and methods?

@CHH
Copy link
Author

CHH commented Oct 31, 2011 via email

@saltybeagle
Copy link

Specifically the protected $bar of the context. I love the idea of transferring the entire context object instead of manually assigning context vars, but re-assigning $this and giving access to protected vars and methods seems like it should be avoided.

@CHH
Copy link
Author

CHH commented Nov 2, 2011

You're right, that should be avoided.

Actually it doesn't have any access to the $bar property. I've messed up with the example code.

I've checked it with 5.4.0beta2 and they now changed the default scoping behaviour of bindTo, so closures don't have access to protected and private class members by default. Actually if you try the example it throws an fatal error, with the reason that the protected property $bar could not be accessed.

So I've fixed the example code by making the bar property public.

Thanks for pointing this out!

@nezarfadle
Copy link

Hi,,

I guess in SimpleTemplate.php we can replace the lines from 41-44 with

extract($locals);

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