PHP实现单例模式最安全的做法


Posted in PHP onJune 13, 2014

作为一种常用的设计模式,单例模式被广泛的使用。那么如何设计一个单例才是最好的呢?

通常我们会这么写,网上能搜到的例子也大部分是这样:

class A
{
    protected static $_instance = null;
    protected function __construct()
    {
        //disallow new instance
    }
    protected function __clone(){
        //disallow clone
    }
    public function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
}
class B extends A
{
    protected static $_instance = null;
}
$a = A::getInstance();
$b = B::getInstance();
var_dump($a === $b);

将__construct方法设为私有,可以保证这个类不被其他人实例化。但这种写法一个显而易见的问题是:代码不能复用。比如我们在一个一个类继承A:
class B extends A
{
    protected static $_instance = null;
}
$a = A::getInstance();
$b = B::getInstance();
var_dump($a === $b);

上面的代码会输出:
bool(true)

问题出在self上,self的引用是在类被定义时就决定的,也就是说,继承了B的A,他的self引用仍然指向A。为了解决这个问题,在PHP 5.3中引入了后期静态绑定的特性。简单说是通过static关键字来访问静态的方法或者变量,与self不同,static的引用是由运行时决定。于是简单改写一下我们的代码,让单例模式可以复用。
class C
{
    protected static $_instance = null;
    protected function __construct()
    {
    }
    protected function __clone()
    {
        //disallow clone
    }
    public function getInstance()
    {
        if (static::$_instance === null) {
            static::$_instance = new static;
        }
        return static::$_instance;
    } 
}
class D extends C
{
    protected static $_instance = null;
}
$c = C::getInstance();
$d = D::getInstance();
var_dump($c === $d);

以上代码输出:
bool(false)

这样,简单的继承并重新初始化$_instance变量就能实现单例模式。注意上面的方法只有在PHP 5.3中才能使用,对于之前版本的PHP,还是老老实实为每个单例类写一个getInstance()方法吧。

需要提醒的是,PHP中单例模式虽然没有像Java一样的线程安全问题,但是对于有状态的类,还是要小心的使用单例模式。单例模式的类会伴随PHP运行的整个生命周期,对于内存也是一种开销。

PHP 相关文章推荐
十天学会php(2)
Oct 09 PHP
如何过滤高亮显示非法字符
Oct 09 PHP
让你同时上传 1000 个文件 (二)
Oct 09 PHP
快速开发一个PHP扩展图文教程
Dec 12 PHP
PHP Opcache安装和配置方法介绍
May 28 PHP
CodeIgniter框架基本增删改查操作示例
Mar 23 PHP
使用WAMP搭建PHP本地开发环境
May 10 PHP
Yii2框架中日志的使用方法分析
May 22 PHP
Yii框架扩展CGridView增加导出CSV功能的方法
May 24 PHP
详细解读php的命名空间(一)
Feb 21 PHP
php实现微信公众平台发红包功能
Jun 14 PHP
PHP实现的权重算法示例【可用于游戏根据权限来随机物品】
Feb 15 PHP
PHP5.5和之前的版本empty函数的不同之处
Jun 13 #PHP
PHP输出英文时间日期的安全方法(RFC 1123格式)
Jun 13 #PHP
PHP中多维数组的foreach遍历示例
Jun 13 #PHP
PHP根据传来的16进制颜色代码自动改变背景颜色
Jun 13 #PHP
php smarty truncate UTF8乱码问题解决办法
Jun 13 #PHP
PHP根据传入参数合并多个JS和CSS文件的简单实现
Jun 13 #PHP
Codeigniter上传图片出现“You did not select a file to upload”错误解决办法
Jun 12 #PHP
You might like
PHP递归复制、移动目录的自定义函数分享
2014/11/18 PHP
laravel5创建service provider和facade的方法详解
2016/07/26 PHP
JavaScript DOM学习第八章 表单错误提示
2010/02/19 Javascript
跨域请求之jQuery的ajax jsonp的使用解惑
2011/10/09 Javascript
jquery 插件学习(四)
2012/08/06 Javascript
Javascript学习笔记之函数篇(四):arguments 对象
2014/11/23 Javascript
jQuery中detach()方法用法实例
2014/12/25 Javascript
JavaScript Math.ceil 方法(对数值向上取整)
2015/01/09 Javascript
jQuery实现的输入框选择时间插件用法实例
2015/02/28 Javascript
简介JavaScript中getUTCMonth()方法的使用
2015/06/10 Javascript
动态创建按钮的JavaScript代码
2016/01/29 Javascript
js验证手机号、密码、短信验证码代码工具类
2020/06/24 Javascript
react脚手架如何配置less和ant按需加载的方法步骤
2018/11/28 Javascript
webpack打包多页面的方法
2018/11/30 Javascript
详释JavaScript执行环境与执行栈
2019/04/02 Javascript
jQuery实现checkbox全选、反选及删除等操作的方法详解
2019/08/02 jQuery
JavaScript页面加载事件实例讲解
2019/09/01 Javascript
vue中利用iscroll.js解决pc端滚动问题
2020/02/15 Javascript
javascript实现画板功能
2020/04/12 Javascript
vue输入框使用模糊搜索功能的实现代码
2020/05/26 Javascript
Python中关于Sequence切片的下标问题详解
2017/06/15 Python
python3.6连接MySQL和表的创建与删除实例代码
2017/12/28 Python
Python爬虫_城市公交、地铁站点和线路数据采集实例
2018/01/10 Python
Python常用库大全及简要说明
2020/01/17 Python
python使用梯度下降和牛顿法寻找Rosenbrock函数最小值实例
2020/04/02 Python
Keras实现将两个模型连接到一起
2020/05/23 Python
序列化Python对象的方法
2020/08/01 Python
基于Python实现全自动下载抖音视频
2020/11/06 Python
CSS3 文字动画效果
2020/11/12 HTML / CSS
印尼值得信赖的在线交易网站:Bukalapak
2019/03/11 全球购物
护理专业自荐信范文
2014/02/26 职场文书
五水共治捐款倡议书
2014/05/14 职场文书
2015年乡镇人大工作总结
2015/04/22 职场文书
《作风建设永远在路上》心得体会
2016/01/21 职场文书
导游词之南京莫愁湖公园
2019/11/13 职场文书
超级详细实用的pycharm常用快捷键
2021/05/12 Python