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新手上路(七)
Oct 09 PHP
PHP flock 文件锁详细介绍
Dec 29 PHP
深入解析php之sphinx
May 15 PHP
基于PHP常用字符串的总结(待续)
Jun 07 PHP
PHP中copy on write写时复制机制介绍
May 13 PHP
php实现的DateDiff和DateAdd时间函数代码分享
Aug 16 PHP
windows7下php开发环境搭建图文教程
Jan 06 PHP
Laravel 5 框架入门(一)
Apr 09 PHP
thinkphp3.x中cookie方法的用法分析
May 19 PHP
PHP正则匹配操作简单示例【preg_match_all应用】
Jul 10 PHP
使用PHP json_decode可能遇到的坑与解决方法
Aug 03 PHP
thinkPHP5框架导出Excel文件简单操作示例
Aug 03 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
PHP5中使用DOM控制XML实现代码
2010/05/07 PHP
PHP检测移动设备类mobile detection使用实例
2014/04/14 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
人脸识别测颜值、测脸龄、测相似度微信接口
2016/04/07 PHP
JS函数实现动态添加CSS样式表文件
2012/12/15 Javascript
jquery提交form表单时禁止重复提交的方法
2014/02/13 Javascript
php读取sqlite数据库入门实例代码
2014/06/25 Javascript
javascript刷新父页面的各种方法汇总
2014/09/03 Javascript
jQuery扁平化风格下拉框美化插件FancySelect使用指南
2015/02/10 Javascript
JS获取图片高度宽度的方法分享
2015/04/17 Javascript
深入解析Javascript闭包的功能及实现方法
2016/07/10 Javascript
BootStrap 动态添加验证项和取消验证项的实现方法
2016/09/28 Javascript
详谈js使用in和hasOwnProperty获取对象属性的区别
2017/04/25 Javascript
Vue.js分页组件实现:diVuePagination的使用详解
2018/01/10 Javascript
JS实现多物体运动的方法详解
2018/01/23 Javascript
JS使用Date对象实时显示当前系统时间简单示例
2018/08/23 Javascript
React注册倒计时功能的实现
2018/09/06 Javascript
vue-自定义组件传值的实例讲解
2018/09/18 Javascript
javascript删除数组元素的七个方法示例
2019/09/09 Javascript
[01:02:00]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第三场 1月24日
2021/03/11 DOTA
python回调函数用法实例分析
2015/05/09 Python
Python实现的计数排序算法示例
2017/11/29 Python
Python语言描述随机梯度下降法
2018/01/04 Python
如何基于python生成list的所有的子集
2019/11/11 Python
pycharm实现在子类中添加一个父类没有的属性
2020/03/12 Python
Pycharm2020.1安装中文语言插件的详细教程(不需要汉化)
2020/08/07 Python
Crocs美国官方网站:卡骆驰洞洞鞋
2017/08/04 全球购物
类如何去实现接口
2013/12/19 面试题
纠纷协议书
2014/04/16 职场文书
活动策划求职信模板
2014/04/21 职场文书
“三支一扶”支教教师思想汇报
2014/09/13 职场文书
国家税务局干部作风整顿整改措施
2014/09/18 职场文书
出纳岗位职责范本
2015/03/31 职场文书
电影雨中的树观后感
2015/06/15 职场文书
Vue过滤器(filter)实现及应用场景详解
2021/06/15 Vue.js
通过T-SQL语句创建游标与实现数据库加解密功能
2022/03/16 SQL Server