Singleton and Late static binding

    The number of Singleton 's in a project is often directly proportional to its complexity and size. Naturally, describing a private constructor, a static property of an object, and the method of obtaining it for any tangible number of classes is a little tedious, and perhaps incorrect. This raises the question: how to “bracken” the implementation of Singleton?

    There may be several options in my opinion. The first is to revise the application architecture. It may be easier to register all objects claiming to be Singleton in a certain collection and access them exclusively through it. This will avoid accidentally creating two copies of the object. However, it is safe to say that there is only one copy of the object in the application at a certain moment of execution, in this scenario it is impossible, since no one can interfere with creating the object directly, bypassing the collection.

    The second way is to implement a Singleton superclass from which all Singleton classes will inherit. However, there is one pitfall in its PHP implementation - late / dynamic bindingin static methods. More precisely, the definition of the name of the current class in the static getInstance method.
    Standard tools like the get_class method cannot be used here, since we actually don’t have any object yet. A reflection comes to mind , but you quickly realize that it has nothing to do with it, since the starting point for it is the name of the object, which we are actually trying to find out.
    And here a mechanism called “late static binding” , available since version 5.3.0, comes to our aid . Its essence is the ability to refer to the called class in the context of static inheritance. In other words, starting with version 5.3.0 we can use the functionget_called_class to get the name of the called class as part of the static method.

    Knowing the above, it is easy to create a superclass to implement the Singleton template.

    1. /**
    2. * Singleton pattern implementation
    3. */
    4. abstract class Singleton {
    6.   /**
    7.    * Collection of instances
    8.    * @var array
    9.    */
    10.   private static $_aInstance = array();
    12.   /**
    13.    * Private constructor
    14.    */
    15.   private function __construct(){}
    17.   /**
    18.    * Get instance of class
    19.    */
    20.   public static function getInstance() {
    22.     // Get name of current class
    23.     $sClassName = get_called_class();
    25.     // Create new instance if necessary
    26.     if( !isset( self::$_aInstance[ $sClassName ] ) )
    27.       self::$_aInstance[ $sClassName ] = new $sClassName();
    28.     $oInstance = self::$_aInstance[ $sClassName ];
    30.     return $oInstance;
    31.   }
    33.   /**
    34.    * Private final clone method
    35.    */
    36.   final private function __clone(){}
    37. }
    * This source code was highlighted with Source Code Highlighter.

    Let's complete the code with a little test

    1. class Example extends Singleton {}
    2. $oExample1 = Example::getInstance();
    3. $oExample2 = Example::getInstance();
    4. echo ( is_a( $oExample1, 'Example' ) && $oExample1 === $oExample2)
    5.   ? 'Same' : 'Different', "\n"; 
    * This source code was highlighted with Source Code Highlighter.

    the result of which will be, you guessed it, "Same."

    It is worth noting that there are mechanisms for obtaining the name of the called class in the context of a static function in PHP version prior to 5.3.0 by analyzing the call stack using the debug_backtrace method . However, in my opinion, this approach is rectal a little more than completely.

    I agree that inheritance is not the best mechanism in this case. In my opinion, if PHP supported annotations and AOP, it would be much more convenient to mark classes with Singleton annotation and implement the aspect that injects the code necessary for implementing Singleton into marked classes. However, as far as I know, neither annotations (as language constructs) nor AOP in PHP are planned in the near future.

    Also popular now: