在 PHP 中,甚至不仅 PHP 中,咱们都会用到全局变量,以保存全局状态。但是,每每全局变量是全局共享的,任何地方任何代码都有可能将其覆盖。例如,咱们定义一个全局变量叫作 PHONE。咱们在某一行代码中,将其定义成了 iPhone,可是咱们不当心在另外一行代码中将其覆写成了 Nokia。这就很是的尴尬了,由于原本咱们并不想它被覆写。php
在一个系统中,咱们会定义许多的方法,生成不少的对象。有时候,咱们会使用不少的方法,对同一个对象作操做。在不使用全局变量的状况下,咱们须要将对象做为参数传入方法中。可是这样传递同一个对象,可能会形成混乱,还可能形成没必要要的依赖。设计模式
其实咱们只须要一个全局可访问的对象就能够解决这个,可是全局变量又会出现咱们上面的说的问题。函数
咱们要解决这些问题,咱们对这样的对象有下面的几个目标。学习
以上的几个目标,就是咱们所须要的,也就是单例模式的特征。this
class Preference { private static $instance; private $props = []; private __construct() {} public static function getInstance() { if (empty(self::$instance)) { self::$instance = new Preference(); } return self::$instance; } public function setProperty($key, $value) { $this->props[$key] = $value; } public function getProperty($key) { return $this->props[$key]; } private function __clone() {} private function __sleep() {} private function __wakeup() {} }
咱们在这里引入了一个私有的构造函数,这样,外部就没法实例化这个对象了。同时,咱们使用 getInstance
方法来获取具体的实例,而没法去覆写它,这就达成了第二个目标。spa
因为 $instance
和 getInstance
都是静态的,因此咱们能够经过 Preference::getInstance()
访问,具体的实例。这样就使得全局均可以访问到它了,它就像全局变量同样了,这就达成了第一个目标了。设计
对于这个类,咱们没法生成第二个对象,由于它的构造函数是私有的,而且 __clone
方法是私有的,并且,getInstance
在判断已经有了一个实例的状况下默认返回该实例。这就达成了第三个目标了。code
同时,咱们也尽可能避免序列化这个实例,因此咱们给 __wakeup
和 __sleep
这两个魔术方法私有。对象
这就是单例模式。rem
对于单例模式,其实没有那么高大上。只不过是更改的对象的访问范围,以及对象始终存在,仅此而已。
最后,本文章是做者在学习设计模式时的感想。部分参考自《深刻 PHP 面向对象、模式与实践(第 3 版)》。若有错误,感谢大神不吝赐教。