Using PHP Closures as View Helpers

In this first part of a two-part tutorial, I develop a basic template system that can parse any type of closure assigned as a property of its view object(s).

Unquestionably, the release of PHP 5.3.x, along with the imminent arrival of PHP 5.4 (at least, at the time of this writing), clearly show the level of maturity that the language has reached in the last few years. The inclusion of support for native namespaces, Late Static Binding, a largely improved SPL and of course the long-awaited traits, are all part of the wealth of niceties that PHP offers to picky developers.

Although most of these features have found their own niche over time (with the sole exception of traits, for obvious reasons), there’s one more that, because of its versatile nature, seems to still be in search of a more solid and defined identity. In this case I’m referring to anonymous functions (AKA closures). At first glance, they don’t seem to fit well in the structure of a language that allows users to tackle the functional and object-oriented paradigms with similar levels of success.

In this case, though, first impressions are misleading. While closures are undeniably superb at  processing all sorts of data via callback functions (the coupling to native array PHP functions like "array_map()" and "array_filter()" are good examples of this), it’s also possible to use them in object-oriented environments and obtain quite impressive results.

Even though real-world examples can be found all over the web, one of the most illustrative projects where closures reveal much of their potential in OOP is Pimple, a small yet powerful dependency injection container created by Fabien Potencier (https://github.com/fabpot/Pimple/blob/master/lib/Pimple.php). While Pimple is indeed a good demonstration of how to use closures in the creation of object graphs without relying on the complexities of reflection and annotations, it’s feasible to take advantage of the functionality of closures in many other use cases.

In this two-part tutorial I’ll be showing you, in a step-by-step fashion, how to use the goodies offered by closures in the implementation of an object-based, easily extendable template system. This system will allow you to embed anonymous functions easily into template files, and call them as typical view helpers, too.

Defining the Template System’s Interfaces

The first step of my plan to construct the template system mentioned above is to define its set of interfaces. In doing so, I’ll be not only honoring the Open/Closed Principle, but I’ll stick more strictly to the commandments of Design by Contract.

With that said, it’s time to declare the first interface. Since the template system must be able to handle view objects in a straightforward fashion, this interface will define a segregated contract for generic views.

The view interface looks like this: 

(MyApplication/ViewInterface.php)

<?php

namespace MyApplication;

interface ViewInterface
{
    /**
     * Set the view template file
     */
    public function setTemplateFile($templateFile);
   
    /**
     * Get the view template file
     */
    public function getTemplateFile();
   
    /**
     * Add a new field to the view
     */
    public function set($name, $value);
   
    /**
     * Get the given field from the view
     */
    public function get($name);
   
    /**
     * Check if the given view field exists
     */
    public function exists($name);
   
    /**
     * Remove the given field from the view
     */
    public function remove($name);
   
    /**
     * Render the view template file
     */
    public function render();              
}

From the above code fragment, it’s pretty clear to see what’s behind the contract defined by the "ViewInterface" interface. Simply put, it declares a set of methods for modeling the basic behavior of generic views. This includes setting and getting a template file, assigning and retrieving fields, and finally rendering the template. It’s not overcomplicated. 

So far, so good. With the earlier interface already set, the next thing we need to do is create a concrete implementer. This will be tasked with spawning view objects. But before I get to that point, I’d like to define an additional interface — which for now will remain unused. However, I’ll be using it when I show you how to dynamically inject into the template system a class that will lazy-load data from a remote resource.

Having clarified that point, here’s the definition of this extra interface:  

(MyApplication/DataHandlerInterface.php)

<?php

namespace MyApplication;

interface DataHandlerInterface
{
    /**
     * Write data to the storage
     */
    public function write($data);
   
    /**
     * Read data from the storage
     */
    public function read();  
}
   
Done. Again, don’t be concerned about the role of the above "DataHandlerInterface" interface, as I’ll be using it later on to extend the initial functionality of my template system. Right now, it’s time to focus only on the relevant things and recap what I’ve managed to do so far. It’s not much, really, as there’s only a granular interface, which defines the contract that must be fulfilled by generic view objects.  

It’s time, therefore, to create a concrete view class, which as I pointed out at the start, must be capable of treating closures as if they were regular template variables.

{mospagebreak title=Handing View Objects: Creating a View Class}

In reality, building a class responsible for creating and handling view objects is a pretty straightforward process; there are many ways to accomplish this without much trouble. In this case, however, there’s an additional challenge: as I explained before, the class must be able to parse all of the variables embedded into its associated template file, including closures.

So, is this somewhat difficult to achieve? Not really. The class below, which implements the previous "ViewInterface" interface, performs this task. Check it out: 

(MyApplication/View.php)

<?php

namespace MyApplication;

class View implements ViewInterface
{
    const DEFAULT_TEMPLATE_FILE = ‘default_template.php';
    protected $_fields = array();
    protected $_templateFile;
   
    /**
     * Constructor
     */
    public function __construct(array $fields = array(), $templateFile = self::DEFAULT_TEMPLATE_FILE)
    {
        // optionally populate the view with an array of values
        if (!empty($fields)) {
            foreach ($fields as $field => $value) {
                $this->$field = $value;
            }
        }
        $this->setTemplateFile($templateFile);
    }
   
    /**
     * Set the view template file
     */
    public function setTemplateFile($templateFile)
    {
        if (!file_exists($templateFile) || !is_readable($templateFile)) {
            throw new InvalidArgumentException(‘The specified template file ‘ . $templateFile . ‘ is invalid.’);
        }
        $this->_templateFile = $templateFile;
        return $this;
    }
   
    /**
     * Get the view template file
     */
    public function getTemplateFile()
    {
       return $this->_templateFile;
    }
   
    /**
     * Reset the template file to the default one
     */
    public function resetTemplateFile()
    {
        $this->_templateFile = self::DEFAULT_TEMPLATE_FILE;
        return $this;
    }
   
    /**
     * Assign a field to the view
     */
    public function set($name, $value)
    {
        return $this->__set($name, $value);
    }
   
    /**
     * Get the given field from the view
     */
    public function get($name)
    {
        return $this->__get($name);
    }
   
    /**
     * Check if the given field has been assigned to the view
     */
    public function exists($name)
    {
        return isset($this->_fields[$name]);
    }
   
    /**
     * Remove the given field from the view
     */
    public function remove($name)
    {
        if (isset($this->_fields[$name])) {
            unset($this->_fields[$name]);
        }
        return $this;
    }
      
    /**
     * Render the template file
     */
    public function render()
    {
        ob_start();
        include $this->_templateFile;
        return ob_get_clean();
    }
   
    /**
     * Assign the given field to the view via the ‘__set()’ magic method
     */
    public function __set($name, $value)
    {
        $this->_fields[$name] = $value;
        return $this;
    }
   
    /**
     * Get the given field from the view via the ‘__get()’ magic method
     */
    public function __get($name)
    {
        if (!isset($this->_fields[$name])) {
            throw new InvalidArgumentException(‘The specified view field ‘ . $name . ‘ does not exist.’);
        }
        return (is_callable($this->_fields[$name]))
            ? $this->_fields[$name]($this)
            : $this->_fields[$name];   
    } 
}    

The above "View" class implements some simple mutators/getters, which allow you to assign, remove and retrieve fields by means of some PHP magic methods. On the other hand, its "render()" method does exactly what it name suggests: it renders the associated template by using a bit of output buffering.

Of course, if you’re anything like me, you’re wondering which part of the class actually parses any closures added to the corresponding template. Well, if you look closely at the "__get()" method, you’ll realize that it first checks to see if the requested field is actually callable. If this is true, then it calls the closure (or any other callable function) and passes to it an instance of the view. This simple yet effective trick allows you to embed variables into a template file, including closures, which can be used as traditional view helpers. Got it? Good.

Naturally, the best way to see if the class can actually treat closures like helpers is by means of a concrete example. Below I created a basic HTML5 template; it contains some interspersed view fields. Have a look at it:
   
(default_template.php)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Using closures in PHP</title>
</head>
<body>
    <header>
        <h1>Header section</h1>
        <h2>Welcome! You’re accessing this page from : <?php echo $this->clientIp;?></h2>
        <p><?php echo $this->header;?></p>
    </header>
    <section>
        <h2>Main section</h2>
        <p><?php echo $this->content;?></p>
    </section>
    <footer>
        <h2>Footer section</h2>
        <p><?php echo $this->footer;?></p>
    </footer>
</body>
</html>

While the structure of this template is pretty simple, it makes reference to a view field called "clientIp," which echoes to screen the IP address from which the user is accessing the web page. Since this data is essentially dynamic, it could be retrieved through a view helper.

Thanks to the functionality of the earlier "View" class, however, the same task can be performed by a closure, as shown below (as usual, the autoloader has been omitted for the sake of brevity):

<?php

use MyApplicationView;

// include the autoloader and create an instance of it
require_once __DIR__ . ‘/Autoloader.php';
$autoloader = new Autoloader;

// create a view object and assign some properties to it
$view = new View;
$view->header = ‘This is the content of the header section';
$view->content = ‘This is the content of the main section';
$view->footer = ‘This is the content of the footer section';

$view->clientIp = function() {
    if (isset($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else {
      return $_SERVER['REMOTE_ADDR'];
    }
};

// render the view template
echo $view->render();

As you can see from the above script, once a new view object has been spawned, it gets assigned some values to its "header," "content," "footer" and "clientIp" fields. Naturally, the most interesting aspect of this process is the use of a closure, which performs a basic check on some server variables to determine the actual IP address of the client.

Leaving apart the limited efficiency of the closure itself (it’ll fail hard when the user is behind an anonymous proxy), the example shows how to encapsulate a specific task inside a closure, which can then be parsed by the view’s "render()" method. Moreover, if you want to see the output generated by the previous script, the following screen capture will hopefully be quite illustrative: 

The script worked decently well. But, what’s the point in using a closure to find out the IP of the client, when the same could be done through a method of a helper object? Since the task is fairly straightforward, a closure does the trick, even at the expense of sacrificing the advantages brought by Polymorphism. For more complex logic, an OO helper would unquestionably  be the right option.

However, there’s a hidden benefit in using a closure as a view field: as you may have noticed, it gets called only when the view’s template is parsed and rendered accordingly. This means that it’s possible to use this approach to perform some expensive operations on request, such a lazy-loading data from a database.    

That’s precisely the use case that I plan to cover in depth in the second part of this tutorial.  

Final Thoughts

In this first chapter of a two-part tutorial, I went through the development of a basic — yet extendable — template system, which could parse any type of closure assigned as a property of its view object(s). In the sample application that you just saw, I used this ability to determine the IP addresses of users accessing the application. This was pretty easy to accomplish.

As I explained before, however, it’s dead simple to use this closure-based approach to perform more complex tasks. To give you proof of my claim, in the final installment, I’ll be showing you how to lazy-load data from a simple text file and embed the corresponding contents into the previous template file. Best of all, I won’t need to amend a single chunk of the entire system.

Don’t miss the last part!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye