Segregated interfaces aren't anything new in PHP. Simply put,a segregated interface is a regular interface whose contract provides implementers with the functionality to perform one or more specific tasks. In this second part of a series, we will be using them to create a registry system.
To demonstrate how to put to work in conjunction all the source classes and interfaces developed so far, I’m going to appeal to the functionality of basic autoloader. This class is very similar to others shown in previous articles published here at the Developer Shed network, so feel free to skip over its definition if you want to. For the sake of completeness, here’s how this autoloader looks:
(Autoloader.php)
<?php
class Autoloader { private static $_instance;
/** * Get the Singleton instance of the autoloader */ public static function getInstance() { if (self::$_instance === null) { self::$_instance = new self; } return self::$_instance; }
/** * Reset the instance of the autoloader */ public static function resetInstance() { self::$_instance = null; }
/** * Prevent to clone the instance of the autoloader */ private function __clone(){}
/** * Load a given class or interface */ public static function load($class) { $file = $class . '.php'; if (!file_exists($file)) { throw new OutOfBoundsException('The file ' . $file . ' containing the requested class or interface ' . $class . ' was not found.'); } require $file; if (!class_exists($class, false) && !interface_exists($class, false)) { throw new OutOfBoundsException('The requested class or interface ' . $class . ' was not found.'); } } }
Certainly, understanding how the above autoloader works is an easy-to-grasp process, so move on and take a peek at the following script, which demonstrates how to save and fetch some trivial data using the earlier array-based registry:
<?php
// example using the ArrayRegistry class
// include the autoloader require_once 'Autoloader.php'; Autoloader::getInstance();
// create an instance of the data handler $dataHandler = new DataHandler(new ArrayRegistry);
// set some data into the data handler $dataHandler->set('fname', 'Alex') ->set('lname', 'Gervasio') ->set('email', 'alex@domain.com');
// get some data from the data handler echo ' First Name: ' . $dataHandler->get('fname') . ' Last Name: ' . $dataHandler->get('lname') . ' Email: ' . $dataHandler->get('email');
This example is indeed pretty basic; it shows how convenient it is to combine the power of dependency injection with the use of segregated interfaces. But, if the pertaining example doesn’t fulfill your expectations yet, pay attention to the following one, which performs the same saving/fetching process but this time by means of the session-based registry:
<?php
// example using the SessionRegistry class
// include the autoloader require_once 'Autoloader.php'; Autoloader::getInstance();
// create an instance of the data handler $dataHandler = new DataHandler(new SessionRegistry);
// set some data into the data handler $dataHandler->set('fname', 'Alex') ->set('lname', 'Gervasio') ->set('email', 'alex@domain.com');
// get some data from the data handler echo ' First Name: ' . $dataHandler->get('fname') . ' Last Name: ' . $dataHandler->get('lname') . ' Email: ' . $dataHandler->get('email');
There you have it. As the earlier code fragment shows, swapping between different registry back-ends is pretty much like replacing a Lego block by another. Plus, thanks to the transparent use of the previous segregated interfaces, each back-end implements only the functionality required to perform the tasks it’s responsible for.
Finally, feel free to tweak all the code samples shown before, something that will let you acquire a better background on segregated interfaces, so you can take advantage of them during the development of your own object-oriented applications.
Final thoughts
Over this second part of the series, I went through the development of a basic registry system, whose respective back-ends used a few custom segregated interfaces to implement the functionality that they needed to perform their corresponding tasks. However simple, this example showed a pretty realistic use case, where the definition of some segregated interfaces made easy to establish the “appropriate” contracts for a set of related classes.
Needless to say that a segregated interface can be utilized in all sort of use cases, others than the one previously discussed. With that concept in mind, in the upcoming tutorial I’m going to demonstrate how to construct a flexible caching system, whose internal classes will made use, not surprisingly, of a user-defined segregated interface as well.