php教程,四种方案实现单例模式,如何禁止多次实例化?
发布于 作者:苏南大叔 来源:程序如此灵动~
单例单例,这个问题是属于老生常谈的问题了。各种编程语言里面针对各种情况,都有各种独特的实现方式。那么,本文中针对的是php中的类,php中类如何实现单例模式呢?换句话就是:在同一个php进程里面,每个类如何实现仅初始化一次。

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验总结。本文测试环境:win10,nginx@1.15.11,php@8.2.10-nts。
技术点一:被实例化的方式
因为目标是在php进程中,禁止类的多次实例化。那么,就需要知道类被实例化的方式。
- 最正统的就是
__construct()方法,通过new class()进行初始化。 - 非正统的克隆
__clone()方法,通过clone $obj来进行初始化。
所以,为了阻止代码意外的通过传统方式初始化成功。需要改写这两个默认方法属性为private,并不是说非要置空方法体内容。只是改成private后,就无法在类外部被意外初始化,会直接报错。例如:
// $aaa = new Sunan();
// Fatal error: Call to private Sunan::__construct() from invalid context// $bbb = clone Sunan::getInstance();
// Fatal error: Call to private Sunan::__clone() from context参考文章:
对于类初始化来说,new self()也是可以初始化的。
技术点二:判断当前类的方法
既然禁用了__construct()方法,就必须自定义初始化的方法了。这里就可能需要用到__CLASS__和get_class()来获得当前类名,以便进行初始化。
这里需要说明的是:__CLASS__和get_class()这两种途径,返回的类名是代码在哪个类里面,就返回哪个类的名字,不考虑继承关系的。
参考文章:
技术点三:static静态变量
静态变量实际上是实现单例模式的关键因素之一,本文中的这几个方案里面,静态变量区别就是存在的位置,或者说作用域的区别。它的特点就是一旦被初始化,就跳出初始化的代码逻辑了,进而升级为一个类似全局变量的特殊存在。
如果要对静态变量的用法,有更多的了解,可以参考:
方案一,类的静态属性
class Sunan{
private function __construct(){}
private function __clone(){}
static $instance = null;
public static function getInstance(){
if (self::$instance == null) {
// self::$instance = new Sunan();
$s = __CLASS__;
self::$instance = new $s;
}
return self::$instance;
}
public function sayHi(){
echo "hi,苏南大叔";
}
}
Sunan::getInstance()->sayHi();
方案二,类静态属性+self
class Sunan2{
private function __construct(){}
private function __clone(){}
private static $instance;
public static function getInstance(){
if (!(self::$instance instanceof self)) {
self::$instance = new self();
}
return self::$instance;
}
public function sayHi(){
return "hi,苏南大叔";
}
}
echo Sunan2::getInstance()->sayHi();
方案三,函数里的静态变量
class Sunan3{
private function __construct(){}
private function __clone(){}
public static function getInstance(){
static $instance;
if (!isset($instance)) {
$c = __CLASS__;
$instance = new $c;
}
return $instance;
}
public function sayHi(){
return "hi,苏南大叔";
}
}
echo Sunan3::getInstance()->sayHi();
方案四,总体管控(工厂模式)
class singleton {
public static function getInstance($class){
static $instances = array();
if (!array_key_exists($class, $instances)) {
$instances[$class] = new $class;
}
$target = $instances[$class];
return $target;
}
}
class Sunan9{
public function sayHi() {
echo "hi,苏南大叔";
}
}
singleton::getInstance('Sunan9')->sayHi();这个方案里面,并没有修改__construct()和__clone()为私有,大家想想看,是为啥呢?

相关文章
- https://newsn.net/say/electron-second-instance.html
- https://newsn.net/say/php-static-method.html
- https://newsn.net/say/php-debug-func.html
- https://newsn.net/say/php-reflect-class.html
结束语
单例模式的存在就是为了资源的整合,比如入数据库查询的时候,如果不使用单例模式的话,每次页面刷新都可能会带来大量的数据库接入操作,进而引发“too many connections”的类似问题。
苏南大叔总结php代码文章,可以参考: