Class inheritance in PHP with Singleton Pattern only works if the instance variable in the inherited class is reinitialized. But why?

邮差的信 提交于 2019-12-22 18:43:23

问题


I have a main class with the singleton function instance() and the associated variable $instance. Now I create several subclasses and let the main class inherit. I do not re-define the singleton function and variable, because of the useful inheritance. Unfortunately, each instance points to the 1st subclass. Only when in the subclasses the $instance variable is initialized to null it works, but why? With the keywords static and not self, the scope should remain in the subclass.

Here is the source code for a better understanding of what I mean:

// PHP Version 7.0
// Don't work as expected:

class base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;

    /*
     * For Singleton Pattern
     */
    public static function instance() {

        if ( null == static::$instance ) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}

class sub11 extends base1
{
    public function test()
    {
        $test = "base1 -> sub11";
        var_dump($test);
    }
}

class sub12 extends base1
{
    public function test()
    {
        $test = "base1 -> sub12";
        var_dump($test);
    }
}

$sub11 = sub11::instance();
$sub12 = sub12::instance();
$sub11->test();
$sub12->test();
// Output:
// string(14) "base1 -> sub11"
// string(14) "base1 -> sub11"  // It's not different!!!

// Work as expected:

class sub21 extends base1
{

    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;  // Is needed, but why?

    public function test()
    {
        $test = "base1 -> sub21";
        var_dump($test);
    }
}

class sub22 extends base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null; // Is needed, but why?

    public function test()
    {
        $test = "base1 -> sub22";
        var_dump($test);
    }
}

$sub21 = sub21::instance();
$sub22 = sub22::instance();
$sub21->test();
$sub22->test();
// Output:
// string(14) "base1 -> sub21"
// string(14) "base1 -> sub22"  // This is correct !

回答1:


In your first part it is working correct and as expected. Both classes sub11 and sub12 using base1's field to store instance. So, the first one, which was instatiated, is placed there and preventing others to overwrite already created instance.

In second part, you specified personal static storage field for each descendant classes, so they uses not base class field, but own field instead (it overlaps parent field, as uses same name).

In a short, first pair of descendant classes uses base1::$instance to check and create instance. Second pair uses own fields, sub21::$instance and sub22::$instance for this task.

You can prevent this by discarding late static binding in base1 class:

class base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;

    /*
     * For Singleton Pattern
     */
    public static function instance() {
        if ( null == self::$instance ) {
        //           ^ self instead of static
            self::$instance = new static();
        //  ^ self instead of static
        }

        return self::$instance;
        //     ^ self instead of static
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}

I do really suggest you to read about late static binding and difference between self and static keywords.

UPDv1:

If you still requiring to get only one instance of each descendant class, you can change singleton method to something like this:

class base1
{
    /*
    * Instances of descendant classes
    * array
    */
    protected static $instances = [];

    /*
     * For Singleton Pattern
     */
    public static function instance() {
        if (empty(self::$instances[static::class])) {
            $instance = new static();

            self::$instances[static::class] = $instance;
        } else {
            $instance = self::$instances[static::class];
        }

        return $instance;
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}


来源:https://stackoverflow.com/questions/45500377/class-inheritance-in-php-with-singleton-pattern-only-works-if-the-instance-varia

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!