PHP7.3:如何在不在子 class 中声明的情况下继承具有最严格范围的受保护静态 属性?

PHP7.3: How can I inherit a protected static property with the thightest possible scope without redeclaring it in the child class?

在我正在处理的应用程序中,MVC 堆栈的模型部分设计为通过单例工作;每个模型都有一个 __getInstanceMethod 即

protected static $singleton;
public static function __getInstance(): self {
    if(self::$singleton === null) {
        self::$singleton = __CLASS__;
        self::$singleton = new self::$singleton;
    }
    return self::$singleton;
}

最终结果是,如果 __getInstance() 在同一个模型 class 上被调用两次,它两次都 returns 完全相同的对象。

我试图通过将 __getInstance() 方法移动到模型的父 class BaseModel 来减少代码重复,方法是像这样编辑它。

class BaseModel {
    protected static $singleton;
    public static function __getInstance(): self {
        if (static::$singleton === null) {
            static::$singleton = static::class;
            static::$singleton = new static::$singleton();
        }
        return static::$singleton;
    }
}
class AModel extends BaseModel {
    protected static $singleton;
    /** ... */
}
class BModel extends BaseModel {
    protected static $singleton;
    /** ... */
}

AModel::__getInstance(); // AModel
BModel::__getInstance(); // BModel

问题是,我需要为每个模型 class 手动添加一个 $singleton 属性,否则我将始终返回第一个模型的实例 class我调用了这个方法。

class BaseModel {
    protected static $singleton;
    public static function __getInstance(): self {
        if (static::$singleton === null) {
            static::$singleton = static::$class;
            static::$singleton = new static::$singleton();
        }
        return static::$singleton;
    }
}
class AModel extends BaseModel {}
class BModel extends BaseModel {}

AModel::__getInstance(); // AModel
BModel::__getInstance(); // Still AModel

有什么办法可以避免这样做吗?

您可以切换到 "instance map",例如:

<?php
declare(strict_types=1);

error_reporting(-1);
ini_set('display_errors', 'On');

class BaseModel
{
    protected static $instances = [];

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

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

class AModel extends BaseModel
{
}

class BModel extends BaseModel
{
}

echo get_class(AModel::__getInstance()), "\n";
echo get_class(BModel::__getInstance());

https://3v4l.org/qG0qJ


在 7.4+ 中可以简化为:

<?php
declare(strict_types=1);

error_reporting(-1);
ini_set('display_errors', 'On');

class BaseModel
{
    private static array $instances = [];

    public static function __getInstance(): self
    {
        return static::$instances[static::class] ??= new static();
    }
}