我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

单例单例,这个问题是属于老生常谈的问题了。各种编程语言里面针对各种情况,都有各种独特的实现方式。那么,本文中针对的是php中的类,php中类如何实现单例模式呢?换句话就是:在同一个php进程里面,每个类如何实现仅初始化一次。

苏南大叔:php教程,四种方案实现单例模式,如何禁止多次实例化? - 多次实例化
php教程,四种方案实现单例模式,如何禁止多次实例化?(图5-1)

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验总结。本文测试环境:win10nginx@1.15.11php@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();

苏南大叔:php教程,四种方案实现单例模式,如何禁止多次实例化? - 单例模式方案一
php教程,四种方案实现单例模式,如何禁止多次实例化?(图5-2)

方案二,类静态属性+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();

苏南大叔:php教程,四种方案实现单例模式,如何禁止多次实例化? - 方案二单例self
php教程,四种方案实现单例模式,如何禁止多次实例化?(图5-3)

方案三,函数里的静态变量

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();

苏南大叔:php教程,四种方案实现单例模式,如何禁止多次实例化? - 单例模式方案三
php教程,四种方案实现单例模式,如何禁止多次实例化?(图5-4)

方案四,总体管控(工厂模式)

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()为私有,大家想想看,是为啥呢?

苏南大叔:php教程,四种方案实现单例模式,如何禁止多次实例化? - 单例模式方案四
php教程,四种方案实现单例模式,如何禁止多次实例化?(图5-5)

相关文章

结束语

单例模式的存在就是为了资源的整合,比如入数据库查询的时候,如果不使用单例模式的话,每次页面刷新都可能会带来大量的数据库接入操作,进而引发“too many connections”的类似问题。

苏南大叔总结php代码文章,可以参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php