Using Late Static Bindings in PHP 5.3

PHP 5.3 introduced a number of valuable features to the popular and constantly developing language, but some of them seem less useful at first glance than they actually are. Late static bindings fall into this category. This article series shows you how to unlock the true power of LSB to work for you.

Without a doubt, PHP is in steady and constant evolution. Its dynamic nature is one of the most relevant factors that has contributed to turning it into the mature language that we see nowadays. This doesn’t mean that its API is a beautiful model of consistence and efficiency, though, especially when compared to older and more solid contenders like C++ and Java.

It’s fair to say, however, that each major release of PHP has been packed with handy features that have made developers’ lives considerably easier (and happier, at least in my personal case). A recent example of this was the introduction a few months ago of PHP 5.3.0. It includes some brand new and exciting characteristics, such as native namespaces, anonymous functions and late static bindings (LSB), aimed at filling some gaps that existed in the language’s API.

The benefits of using namespaces are quite obvious, as they prevent class names from clashing in an elegant and effective fashion. Needless to say, anonymous functions (AKA closures) allow developers to do all sorts of clever things in the code, such as use functions as callback parameters, or even assign a complex function to a single variable (if you’ve worked with JavaScript since the old pre-jQuery days, you know what I’m talking about here).

But what’s special about  late static bindings? At first sight, it seems that LSB offers nothing or little of importance, as it only permits you to determine at run time what class has been called in a static context.

However, this is a misleading impression, trust me. In reality, LSB is a feature so powerful that it makes the upgrade to PHP 5.3 worthwhile all by itself. Let me elaborate on this concept a bit further with a simple example: say that you’ve created a base class which defines a static Singleton method that returns the corresponding instance by referencing the class with the keyword “self” or the constant __CLASS__ . This is fine, as long as you don’t need to extend the class in question and call the method from one of multiple subclasses. If you do so prior to PHP 5.3, you’ll always get an instance of the parent, not of the child classes, since a static call to “self” or __CLASS will be resolved at compiling time.

Fortunately, LSB addresses this issue by determining which class has been referenced in a static context at runtime. Of course, the theoretical side of this feature needs to be backed up with functional code. Given that, in the lines to come I’m going to create some approachable examples that hopefully will help you understand how to put LSB to work for you. 

{mospagebreak title=Why late static binding is so useful}

As noted in the introduction, the first impression that some developers have when they hear about LSB is that it’s simply a minor, rather irrelevant improvement of the language. To demonstrate how useful this feature is in reality, I’m going to recreate a fictional scenario where it’s necessary to define a base abstract registry class, whose functionality and structure will be inherited and eventually refined by one or more subclasses. 

Simply put, the definition of this abstract registry will look as follows:

(RegistryAbstract.php)

 

 

 

 

abstract class RegistryAbstract

{

    protected static $_instances = array();

   

    // get Singleton instance of the registry

    public static function getInstance()

    {

        $class = self::getClass();

        if (!isset(self::$_instances[$class]))

        {

            self::$_instances[$class] = new $class;

        }

        return self::$_instances[$class];

    }

 

 

    public static function getClass()

      {

        return __CLASS__;

    }

        

    // 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();         

}

As you can see, the previous “RegistryAbstract” class declares some abstract setter and getter methods that will allow you to create concrete child registries for fetching and saving data to a predefined storage mechanism, such as a vanilla array, a session variable or a database. Note the implementation of a static “getInstance()” method, which in theory returns a Singleton instance of the current registry via the “getClass()” method.

Since this base abstract class should always be refined by one or multiple implementations, it’s time to derive a subclass from it, which in this case will be an array-based registry. Here’s the definition of this concrete class:

(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;

    }

 

 

    // clear the registry

    public function clear()

    {

        $this->_data = array();

    }         }        

}

Grasping the logic driving the previous “ArrayRegistry” class is a pretty straightforward process; it simply implements the abstract methods defined by its parent to store and retrieve data from a private array. I don’t want to sound pedantic, but apparently it looks like this concrete registry will work like a charm.

Unfortunately, things can be really tricky sometimes, because the hard truth is that any attempt to call the class’s inherited “getInstance()” method will cause the PHP engine to throw a fatal error. But how is this possible if the method in question exactly returns an instance of the array registry? Well, in its current state, what the method really does is grab an instance of its parent, which is obviously a big problem, since this one is abstract.

It’s probable, however, that this explanation sounds a bit confusing to you, so in the next section I’m going to code a hands-on example that will recreate the condition previously described.

Now, to learn what’s wrong with the “ArrayRegistry” class, click on the link below and keep reading.

{mospagebreak title=Attempting to grab an instance of an abstract registry class}

Unless you perform smart unit tests with your classes (which is recommended), they may display an unexpected, erroneous behavior under certain conditions. That’s exactly the case with the array-based registry defined in the previous section, even though it seems as if it would work correctly.

To demonstrate this, below I created a simple script which attempts to grab an instance of the registry via its Singleton “getInstance()” method. Check it out:  

// include the source classes

require_once ‘RegistryAbstract.php’;

  require_once ‘ArrayRegistry.php’;

 

 

// try to grab the Singleton instance of the ArrayRegistry class

$arrayRegistry = ArrayRegistry::getInstance();

 

 

/* this is a static method call that attempts to return an instance of the abstract registry, thus throwing the following error:

Cannot instantiate abstract class RegistryAbstract in path/to/AbstractRegistry.php

*/      

That was quite a big surprise, eh? Whenever the script calls up the method in question, the PHP engine complains loudly and raises a fatal error stating that the “RegistryAbstract” class is abstract, and therefore it can’t be instantiated, even though the purpose from the very beginning was to create an object from the array registry. Well, this happened because of the implementation of the “getInstance()” method. This method resolves the called class at compiling time via the keyword “self,” which in this case always returns the abstract parent. Got the point? I hope so.

However, not all is lost with the earlier example, since late static bindings address these and other issues related to static class hierarchies by using the familiar keyword “static.” Naturally, the best way to understand how this feature works is by example, so in the following section I’m going to modify the definitions of the previous registry classes. This time, they’ll work as expected.

To see how this will be done, jump ahead and read the next few lines.

{mospagebreak title=Fixing things with late static bindings}

As I said before, LSB uses the keyword “static” to resolve at runtime conflicts that may occur in static contexts, like the one that you saw in the preceding section. To make the pertinent registry classes behave correctly, it’s necessary to tweak  their definitions. So first, here’s how the base “RegistryAbstract” looks when we use late static bindings within its “getInstance()” method:

(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) RegistryException.php)

 

 

 

 

<?php

 

 

class RegistryException extends Exception{}

As you may have noticed, the “getClass()” method is now called using the expression “static::getClass()” instead of the typical “self::getClass(),” which implies that the method will always be executed in the scope of the calling class. In other words, if the method is invoked by the abstract parent, it will raise an exception, which is the expected behavior; but when called inside the concrete array registry class, it will behave like this:

(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();

    }        

}

Here’s the amended version of “getClass().” Now, when called from inside the previous “ArrayRegistry” class, the “getInstance()” method will effectively return an instance of this concrete registry, thanks to the functionality provided by late static bindings. The implementation of this Singleton method could be simplified by using another handy function included with PHP 5.3, named “get_called_class(),” but the details of this process will be discussed in an upcoming tutorial of this series.

In the meantime, feel free to edit the source code of the previous registry classes. This process will arm you with a more solid background in working with LSB.

Final thoughts

In this first part of the series, I provided you with a concrete example that demonstrated how to use the feature called Late Static Bindings introduced in PHP 5.3.0. As you saw, it allows to solve problems that may arise when working with a static hierarchy of classes.

It’s fair to say, however, that the aforementioned example in its current state looks rather incomplete, since it doesn’t include a script that shows how to put the registry classes defined so far to work together. Since I plan to create such a script in the next tutorial, I recommend you don’t miss it!   

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

chat sex hikayeleri Ensest hikaye