Search code examples
phpoopsingletonextend

Extending a singleton class


i used to create an instance of a singleton class like this:

$Singleton = SingletonClassName::GetInstance();

and for non singleton class:

$NonSingleton = new NonSingletonClassName;

i think we should not differentiate how we create an instance of a class whether this is a singleton or not. if i look in perception of other class, i don't care whether the class we need a singleton class or not. so, i still not comfortable with how php treat a singleton class. i think and i always want to write:

$Singleton = new SingletonClassName;

just another non singleton class, is there a solution to this problem ?


Solution

  • I wouldn't recommend it as it would make your code a lot harder to understand (People think new means an entirely new object). But then I wouldn't recoemmed the use of Singletons.

    The basic idea of this code is that there is a wrapper around a singleton. All functions and variables accessed through that wrapper actually effect the singleton. It isn't perfect as the code below doesn't implement a lot of magic methods and SPL interfaces but they can be added in if required

    Code

    /**
     * Superclass for a wrapper around a singleton implementation
     *
     * This class provides all the required functionality and avoids having to copy and
     * paste code for multiple singletons.
     */
    class SingletonWrapper{
        private $_instance;
        /**
         * Ensures only derived classes can be constructed
         *
         * @param string $c The name of the singleton implementation class
         */
        protected function __construct($c){
            $this->_instance = &call_user_func(array($c, 'getInstance'));
        }
        public function __call($name, $args){
            call_user_func_array(array($this->_instance, $name), $args);
        }
        public function __get($name){
            return $this->_instance->{$name};
        }
        public function __set($name, $value){
            $this->_instance->{$name} = $value;
        }
    }
    
    /**
     * A test singleton implementation. This shouldn't be constructed and getInstance shouldn't
     * be used except by the MySingleton wrapper class.
     */
    class MySingletonImpl{
        private static $instance = null;
        public function &getInstance(){
            if ( self::$instance === null ){
                self::$instance = new self();
            }
            return self::$instance;
        }
    
        //test functions
        public $foo = 1;
        public function bar(){
            static $var = 1;
            echo $var++;
        }
    }
    
    /**
     * A wrapper around the MySingletonImpl class
     */
    class MySingleton extends SingletonWrapper{
        public function __construct(){
            parent::__construct('MySingletonImpl');
        }
    }
    

    Examples

    $s1 = new MySingleton();
    echo $s1->foo; //1
    $s1->foo = 2;
    
    $s2 = new MySingleton();
    echo $s2->foo; //2
    
    $s1->bar(); //1
    $s2->bar(); //2