仅当重新初始化继承类中的实例变量时,PHP 中使用单例模式的类继承才有效。但为什么?

2024-04-10

我有一个带有单例函数的主类实例()和相关变量$实例。现在我创建几个子类并让主类继承。我没有重新定义单例函数和变量,因为继承很有用。不幸的是,每个实例都指向第一个子类。仅当在子类中$实例变量被初始化为null它有效,但为什么呢?有了关键词static并不是self,范围应保留在子类中。

这是源代码,可以更好地理解我的意思:

// 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 !

在你的第一部分它正在工作correct和预期的一样。两个班sub11 and sub12 using base1的字段来存储实例。因此,第一个已启动的实例被放置在那里并防止其他人覆盖已经创建的实例。

在第二部分中,您为每个后代类指定了个人静态存储字段,因此它们不使用基类字段,而是使用自己的字段(它与父字段重叠,因为使用相同的名称)。

简而言之,第一对后代类使用base1::$instance检查并创建实例。第二对使用自己的字段,sub21::$instance and sub22::$instance为了这个任务。

您可以通过丢弃后期静态绑定来防止这种情况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);
    }
}

我真的建议你阅读后期静态绑定 http://php.net/manual/en/language.oop5.late-static-bindings.php和之间的区别self and static关键词。

UPDv1:

如果您仍然需要仅获取每个后代类的一个实例,您可以将 singleton 方法更改为如下所示:

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);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅当重新初始化继承类中的实例变量时,PHP 中使用单例模式的类继承才有效。但为什么? 的相关文章

随机推荐