Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Singleton design pattern inheritance error

From php singleton class below

<?php
class Singleton
{
    /**
     * @var Singleton The reference to *Singleton* instance of this class
     */
    private static $instance;

    /**
     * Returns the *Singleton* instance of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }
}

I am trying to inherit new child class

class SingletonChild extends Singleton {
}

but when I do testing

$obj = Singleton::getInstance();
$obj_two = SingletonChild::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)
var_dump($obj === $obj_two);   // false

I'm getting php fatal error.

PHP Fatal error: Uncaught Error: Cannot access property SingletonChild::$instance

like image 889
Wimal Weerawansa Avatar asked May 10 '16 12:05

Wimal Weerawansa


2 Answers

You made $instance private, which means it cannot be inherited. Change it to protected

protected static $instance;

The manual discusses the individual uses of visibility

http://php.net/manual/en/language.oop5.visibility.php

So it looks like the hangup is in your edit

$obj = Singleton::getInstance();
$obj_two = SingletonChild::getInstance();
var_dump($obj === $obj_two);   // false

This will never be true. getInstance gets an instance of the current class. Since they are different classes they are not the same. Doing a test like this is sloppy, however. I would never do a test on an object like this. What would make more sense is to make sure that you're getting an instance of Singleton which can be done very easily like so

if($obj_two instanceof Singleton) // true

Because the child inherits the parent, it is an instance of the parent

like image 179
Machavity Avatar answered Oct 22 '22 04:10

Machavity


Inheriting Singleton class in PHP is difficult, event in PHP 7.0, but you can do this with some changes on your class to work.

first make your Singleton class to abstract

abstract class Singleton {

}

change your $instance variable to array $instance(s)

private $instances = [];

Now change getInstance() method like below

public static function getInstance() {
  if (!isset(self::$instances[static::class]) {
    self::$instances[static::class] = new static();
  }

  return self::$instances[static::class];
}

And change your test

remember now you can't call Singleton:: getInstance() due to abstract

class SingletonChild extends Singleton {
}

class SingletonChildTwo extends SingletonChild {
}

$obj = SingletonChild::getInstance();
$obj_two = SingletonChildTwo::getInstance();
var_dump($obj === SingletonChild::getInstance()); // true
var_dump($obj === $obj_two); // will -> false
like image 22
Kamaal ABOOTHALIB Avatar answered Oct 22 '22 02:10

Kamaal ABOOTHALIB