As usual, before I start digging deeper into the use of the “get_called_class()” function referenced in the introduction, I'm going to take a brief look at the example developed in the last part of the series. It demonstrated how to take advantage of the functionality offered by late stating bindings to implement a basic hierarchy of registry classes. With that said, here’s the source code corresponding to the first of these classes, which defines the structure and partial behavior of a generic registry. Here it is: (RegistryAbstract.php) abstract class RegistryAbstract { protected static $_instances = array();
// get Singleton instance of the registry public static function getInstance() { // the static call to 'getClass()' is resolved at runtime $class = static::getClass(); if (!isset(self::$_instances[$class])) { self::$_instances[$class] = new $class; } return self::$_instances[$class]; }
// throw an exception as this class can't be instantiated protected static function getClass() { throw new RegistryException('This class is abstract and cannot be instantiated!'); }
// implemented by registry subclasses abstract public function set($key, $value);
// implemented by registry subclasses abstract public function get($key);
// implemented by registry subclasses abstract public function clear(); } (RegistryException.php) <?php class RegistryException extends Exception{} As you can see, the “RegistryAbstract” class is nothing but a basic Singleton that declares a few intuitive methods which should be implemented by flyweight registries. Of course, the most relevant section of this class is the definition of “getInstance(),” which utilizes late static bindings to resolve at runtime calls to the static “getClass()” method. To help you understand the inner workings of this process more clearly, here’s a subclass derived from the previous abstract parent that can be used for saving and retrieving data from an internal array. Check it out: (ArrayRegistry.php) <?php class ArrayRegistry extends RegistryAbstract { private $_data = array();
// save data to the registry public function set($key, $value) { $this->_data[$key] = $value; return $this; }
// get data from the registry public function get($key) { return isset($this->_data[$key]) ? $this->_data[$key] : null; } // get called class public static function getClass() { return __CLASS__; } // clear the registry public function clear() { $this->_data = array(); } } To be frank, the only thing worth noting about the above “ArrayRegistry” class is that it overrides the inherited “getClass()” method to return an instance of itself to client code. With this concrete registry already set, the next thing we need to do is create a basic autoloader that includes the previous classes automatically. Here’s one that performs that task pretty decently: (Autoloader.php) <?php class Autoloader { private static $_instance;
// get Singleton instance of the autoloader public static function getInstance() { if (!self::$_instance) { self::$_instance = new self; } return self::$_instance; }
// private constructor private function __construct() { spl_autoload_register(array($this, 'autoload')); }
// prevent cloning instance of the autoloader private function __clone(){}
// autoload classes on demand public static function autoload($class) { $file = $class . '.php'; if (!file_exists($file)) { require_once 'FileNotFoundException.php'; throw new FileNotFoundException('The file containing the requested class was not found.'); } require $file; unset($file); if (!class_exists($class, false)) { require_once 'ClassNotFoundException.php'; throw new ClassNotFoundException('The requested class was not found.'); } } } (FileNotFoundException.php) <?php class FileNotFoundException extends Exception{} (ClassNotFoundException.php) <?php class ClassNotFoundException extends Exception {} Understanding the logic that drives the previous autoloader is a straightforward process, so for the sake of brevity I’m not going to waste your time explaining how it works. Instead, I suggest you look at the following code fragment, which shows how to use all of the classes coded before in a quite useful way: <?php try { require_once 'Autoloader.php'; // grab the Singleton instance of the autoloader $autoloader = Autoloader::getInstance(); // grab the Singleton instance of the ArrayRegistry class $arrayRegistry = ArrayRegistry::getInstance(); // save some users to the registry $arrayRegistry->set('user1', 'Julie Smith')->set('user2', 'Mary Wilson'); // get the last user from the registry echo $arrayRegistry->get('user2'); /* displays the following Mary Wilson */ } catch (Exception $e) { echo $e->getMessage(); exit(); } Admittedly, this script isn’t the most useful piece of code that you’ll find on the web, but it shows a couple of things worth noticing here: first, it’s extremely simple to implement a hierarchy of Singleton registries, and last but not least, this has been accomplished thanks to the use behind the scenes of late static bindings. Even though this feature can be used to do many clever things in a static context other than creating flyweight registries, the truth is that there are certain use cases where it can be replaced directly by the “get_called_class()” function mentioned at the beginning of this tutorial. This function is in reality an equivalent of LSB, as it allows you to retrieve the name of the class from which a static method has been called. This is identical to the statement “static::getClass()” coded within the “getInstance()” method that you saw a moment ago. To demonstrate how to work with this function, in the coming section I’m going to modify the definitions of the previous registry classes, which this time will use the function in question to do their business. To learn the full details of this process, jump ahead and read the lines to come.
blog comments powered by Disqus |
|
|
|
|
|
|
|