<?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对象,在声明init = new FactorySingle();。这样可以省略掉getInit()方法,但是这个静态变量不管用不用都会直接实例化出来占用内存。这种单例就叫做饿汉式单例模式。
-
我们的 PHP 代码和例子很明显不是饿汉式的,因为声明变量不能是表达式,这种形式叫做懒汉式。你要主动的来用getInit()获取,我才会创建对象。
-
懒汉式在多线程的应用中,如java多线程或者PHP中使用swoole之后,会出现重复创建的问题,而且这多次创建的都不是同一个对象了。这时一般会使用双重检测来来确保全局还是只有唯一的一个对象。具体代码大家可以去自己找一下。饿汉式不会有问题,饿汉式本身就已经给静态属性赋值了,不会再改变。具体可以参考静态类相关文章(公众号内查询《PHP中的static》或掘金juejin.im/post/5cb5b2…