PHP设计模式--单例模式

62 阅读1分钟
<?php

/**
 * 单例模式 : 只能获得一个对象
 */
class FactorySingle{
    public $num=0;
    protected static $init = null;
    protected function __construct(){
        $this->num = mt_rand(111111,999999);
    }

    public static function getInit(){
        if(self::$init===null){
            self::$init = new FactorySingle();
        }
        return self::$init;
    }

}

$s1 = FactorySingle::getInit();
$s2 = FactorySingle::getInit();

var_dump($s1,$s2,$s1===$s2);

$s1->num = 88888;

var_dump($s1,$s2,$s1===$s2);

没错,核心就是这样一个单例类,没别的了。让静态变量保存实例化后的自己。当需要这个对象的时候,getInit()方法获得全局唯一的一个对象。

客户端的调用,我们会发现s1和s2是完全一样的对象。

  • 没错,从代码中就可以看出,单例最大的用途就是让我们的对象全局唯一。

  • 那么全局唯一有什么好处呢?有些类的创建开销很大,而且并不需要我们每次都使用新的对象,完全可以一个对象进行复用,它们并没有需要变化的属性或状态,只是提供一些公共服务。比如数据库操作类、网络请求类、日志操作类、配置管理服务等等

  • 曾经有过面试官问过,单例在PHP中到底是不是唯一的?如果在一个进程下,也就是一个fpm下,当然是唯一的。nginx同步拉起的多个fpm中那肯定就不是唯一的啦。一个进程一个嘛!

  • 单例模式的优点:对唯一实例的受控访问;缩小命名空间;允许对操作和表示的精化;允许可变数目的实例;比类操作更灵活。

  • Laravel中在IoC容器部分使用了单例模式。关于容器部分的内容我们会在将来的Laravel系列文章中讲解。我们可以在Illuminate\Container\Container类中找到singleton方法。它调用了bind方法中的getClosure方法。继续追踪会发现他们最终会调用Container的make或build方法来进行实例化类,不管是make还是build方法,他们都会有单例的判断,也就是判断类是否被实例化过或者在容器中已存在。build中的if (!$reflector->isInstantiable())。

  • 在Java等静态语言中,静态变量可以直接new对象,在声明instance的时候直接给他赋值,比如protectedstaticinstance的时候直接给他赋值,比如 protected static init = new FactorySingle();。这样可以省略掉getInit()方法,但是这个静态变量不管用不用都会直接实例化出来占用内存。这种单例就叫做饿汉式单例模式。

  • 我们的 PHP 代码和例子很明显不是饿汉式的,因为声明变量不能是表达式,这种形式叫做懒汉式。你要主动的来用getInit()获取,我才会创建对象。

  • 懒汉式在多线程的应用中,如java多线程或者PHP中使用swoole之后,会出现重复创建的问题,而且这多次创建的都不是同一个对象了。这时一般会使用双重检测来来确保全局还是只有唯一的一个对象。具体代码大家可以去自己找一下。饿汉式不会有问题,饿汉式本身就已经给静态属性赋值了,不会再改变。具体可以参考静态类相关文章(公众号内查询《PHP中的static》或掘金juejin.im/post/5cb5b2…

感谢分享:mp.weixin.qq.com/s?__biz=MzI…