PHP单例模式父类instance方法实现代码详解

分享于:2020-09-18 11:06:41

对某一类实现单例模式,为了节省代码,避免每个类都重复书写一样的代码,可以为所有实现单例的类定义一个父类:

abstract class Common{

    protected static $_instance;
    protected function __construct(){}
    public static function instance(): Common
    {}
}

class Auth extends Common{}
class Ip extends Common{}



思考下,instance静态方法怎么书写,按这样写:

if(is_null(self::$_instance)) self::$_instance = new self();
return self::$_instance;


肯定是不对的,不管是执行  Auth::instance()   还是 Ip::instance()  ,“self”永远指的是Common类,因为Common类是抽象类,不能实例化,会报错的。《类的范围解析操作符

Cannot instantiate abstract class app\extend\Common


把“self”改成“static”

if(is_null(self::$_instance)) self::$_instance = new static();
return self::$_instance;


当执行  Auth::instance()   或  Ip::instance() 时,貌似是可以了


2020-09-18_104233.png

2020-09-18_104233.png

实现单例了,但如果执行一次脚本,先后执行了  Auth::instance()   、  Ip::instance()  ,就会发现新的问题,  Ip::instance()  返回的是Auth对象,具体的原因一分析就能知道,写的代码逻辑是有错误的:


 self::$_instance 等同于 Common::$_instance ,Auth类、Ip类执行instance静态方法,赋值获取的都是Common父类的$_instance静态属性,所以执行  Ip::instance() , self::$_instance 已被提前执行的   Auth::instance()  赋值为Auth对象实例。


怎么去改呢?如果这样,把 self::$_instance 改成 static::$_instance

if( is_null(static::$_instance) ) static::$_instance = new static();
return static::$_instance;


其实也不行,虽然在Auth类 static::$_instance 等同于 Auth::$_instance ,在Ip类 static::$_instance 等同于 Ip::$_instance ,可Auth类、Ip类并没有$_instance静态属性,在《第七章:第9节 PHP面向对象——重写》有过总结“子类调用父类的方法访问成员变量子类没有则访问父类的成员变量;”所以 static::$_instance 最终等同于 Common::$_instance  。


如果所有的子类都有自己的$_instance静态属性,那就不会出现错误了。最终代码:


abstract class Common{

    protected static $_instance;
    protected function __construct(){}
    public static function instance(): Common
    {
         if( is_null(static::$_instance) ) static::$_instance = new static();
             return static::$_instance;
    }
}

class Auth extends Common{
    protected static $_instance;
}
class Ip extends Common{
    protected static $_instance;
}


每个子类都需要加$_instance静态属性才可以,这样的代码设计很不好,如果有些类忘记加了,岂不是又会出现错误。代码可以这样优化:


abstract class Common{

    protected static $_instance;
    protected function __construct(){}
    public static function instance(): Common
    {
         if( empty(self::$_instance[static::class]) ) self::$_instance[static::class] = new static();
             return self::$_instance[static::class];
    }
}

class Auth extends Common{}
class Ip extends Common{}


self::$_instance 也可以改成 static::$_instance 。