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 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 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.
blog comments powered by Disqus |
|
|
|
|
|
|
|