简体   繁体   中英

Using clousers to handle templates in PHP

There is like a million Template Engine for PHP (Blade, Twig, Smarty, Mustache, ...), and i just hate the idea of creating a new syntax and compiler to write PHP inside HTML! I think it's just not smart (but this isn't what i am here to discuss :) ), what is wrong with writing PHP+HTML the usual way - not for logic - you know, all the variables and loops and defines you wanna use without this {{% %}} or that {:: ::} ! At least for performance sake!

Now, i am using Laravel these days , and it's awesome; it offers (besides Blade and any other 3rd party engine) a plain PHP templates system that uses ob_start/include/ob_get_clean and eval. I was very happy to know that i can avoid learning a new syntax to write PHP inside HTML.

Here is what i am suggesting; what about instead of using ob_* functions with include, we use Closures ? Here is a simple class i put together just to make a point :

class Templates{

static public $templates    = array();

static public function create($name, $code){
    self::$templates[$name] = $code;
}

static public function run($name, $data){
    if(!isset(self::$templates[$name]) || !is_callable(self::$templates[$name])) return false;
    return call_user_func(self::$templates[$name], $data);
}

}

And here is how to use it:

Templates::create('test', function($data){
    return 'Hi '.$data['name'].' ! ';
});

for($i =0; $i < 10; $i++){
    print Templates::run('test', array('name' => 'Jhon'));
}

I think this way is much better, since i wont need to do any output buffering or use eval. And to "separate concerns" here, we can put the Templates::create code in a separate file to keep things clean, in fact this way things can become more simple and elegant; we can make another method to load the template file:

static public function load($name){
    self::create($name, include($name.'.php'));
}

And the content of the template file will be as simple as this:

return function($data){
    return 'Hi '.$data['name'].' ! ';
};

What do you think of this ? Is there any problems with the approach or the performance of such use of Closures ?

I do not think there are any problems besides that if you put all closure functions into array, that would possibly mean that functions are kinda doing basically the same stuff.

What I mean by this:

In your example you have your functions accepting only 1 parameter. So, not to create a mess all functions you create would accept the same set of parameters and return the same type of data .

However when declared apart, functions may be supposed to do something different and unique.

Why such a solution is suitable: when using some engines, there may be a lot of different functions declared already. To resolve the conflict, they can be "hidden" inside arrays.

Also, some people even say that anonymous functions can be generally better in case of performance. But we have to test that first: to call a function you:

  1. Call a static function run
  2. Check a function for existence
  3. Check a function for callability
  4. And then use call_user_func which returns the return of your function. So, 3x return.

Update

My recomendations for you code:

Make all possible checks only when creating a function. That will greatly buff performance.

static public function create($name, $code){
  if (!isset(self::$templates[$name])){
    if (is_callable($code)){
      self::$templates[$name] = $code ;
    } else {
      //func is not callable, Throw an exception.
    }
  } else {
    //function already exists. Throw an exception.
  }
}

That way you just can have 2x increase in performance:

static public function run($name, $data){
  if (isset(self::$templates[$name])){
    self::$templates[$name]($data); //Just make a straight call
  } else {
    //throw new Exception(0, "The func is not defined") ;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM