<?phpclass Singleton{/*** Singleton的实例存储在一个静态字段中。 该字段是一个数组,因为我们将让我们的Singleton具有子类。* 该数组中的每个项目都是特定Singleton子类的实例。 稍后您将了解其工作原理* @var array*/private static $instances = [];/*** Singleton的构造函数应始终是私有的,以防止使用new运算符直接进行构造调用* Singleton constructor.*/protected function __construct(){}/*** 单例不应该是可克隆的*/protected function __clone(){}/*** 单例不应该从字符串中恢复 unserialize()调用抛出异常*/public function __wakeup(){throw new \Exception("Cannot unserialize a singleton.");}/*** 这是控制对单例实例的访问的静态方法。 在第一次运行时,它将创建一个单例对象并将其放置到静态字段中。* 在随后的运行中,它返回存储在静态字段中的客户端现有对象。* 此实现使您可以在继承每个子类一个实例的同时,对Singleton类进行子类化* @return Singleton*/public static function getInstance(): Singleton{$cls = static::class;if (!isset(self::$instances[$cls])) {self::$instances[$cls] = new static();var_dump(self::$instances);}return self::$instances[$cls];}/*** 任何单例都应该定义一些业务逻辑,这些逻辑可以在其实例上执行。*/public function someBusinessLogic(){echo 'current class ' . static::class . PHP_EOL;}}$aa = Singleton::getInstance();$bb = Singleton::getInstance();var_dump($aa === $bb);$aa->someBusinessLogic();$bb->someBusinessLogic();class Db extends Singleton{}class RedisSingleton extends Singleton{}$db1 = Db::getInstance();$db2 = Db::getInstance();$db1->someBusinessLogic();$db2->someBusinessLogic();$redis1 = RedisSingleton::getInstance();$redis2 = RedisSingleton::getInstance();$redis1->someBusinessLogic();$redis2->someBusinessLogic();
输出
array(1) {["Singleton"]=>object(Singleton)#1 (0) {}}bool(true)current class Singletoncurrent class Singletonarray(2) {["Singleton"]=>object(Singleton)#1 (0) {}["Db"]=>object(Db)#2 (0) {}}current class Dbcurrent class Dbarray(3) {["Singleton"]=>object(Singleton)#1 (0) {}["Db"]=>object(Db)#2 (0) {}["RedisSingleton"]=>object(RedisSingleton)#3 (0) {}}current class RedisSingletoncurrent class RedisSingleton
