In the application I’m working on, the Model part of the MVC stack is designed to work trough singletons; each Model has a __getInstanceMethod which is
protected static $singleton; public static function __getInstance(): self { if(self::$singleton === null) { self::$singleton = __CLASS__; self::$singleton = new self::$singleton; } return self::$singleton; }
End result is, if __getInstance() is called twice on the same Model class, it returns the same exact object both times.
I tried to reduce code duplication by moving the __getInstance() method to the Model’s parent class, BaseModel, by editing it like so.
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
Problem is, I need to manually add a $singleton property to each and every Model class, otherwise I’ll always get returned the instance of the first Model class I called the method on.
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
Is there a way I can avoid doing that?
Advertisement
Answer
You could switch to an “instance map”, e.g.:
<?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());
and with 7.4+ it could be simplified to:
<?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(); } }