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 各种应用乱码问题的解决方法
May 09 PHP
解析PHP提交后跳转
Jun 23 PHP
几个实用的PHP内置函数使用指南
Nov 27 PHP
ThinkPHP入口文件设置及相关注意事项分析
Dec 05 PHP
php验证邮箱和ip地址最简单方法汇总
Oct 30 PHP
PHP数组游标实现对数组的各种操作详解
Jan 26 PHP
thinkPHP3.x常量整理(预定义常量/路径常量/系统常量)
May 20 PHP
php中的登陆login实例代码
Jun 20 PHP
php安装ssh2扩展的方法【Linux平台】
Jul 20 PHP
ThinkPHP发送邮件示例代码
Oct 08 PHP
PHP+redis实现的购物车单例类示例
Feb 02 PHP
phpinfo无法显示的原因及解决办法
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作的文本留言本的例子(四)
2006/10/09 PHP
PHP Memcached + APC + 文件缓存封装实现代码
2010/03/11 PHP
PHP中创建空文件的代码[file_put_contents vs touch]
2012/01/20 PHP
php将文本文件转换csv输出的方法
2014/12/31 PHP
postfixadmin忘记密码后的修改密码方法详解
2016/07/20 PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
2017/08/03 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
JS效率个人经验谈(8-15更新),加入range技巧
2007/01/09 Javascript
基于SVG的web页面图形绘制API介绍及编程演示
2013/06/28 Javascript
js实现浏览器的各种菜单命令比如打印、查看源文件等等
2013/10/24 Javascript
js匿名函数作为函数参数详解
2016/06/01 Javascript
jQuery插件zTree实现获取一级节点数据的方法
2017/03/08 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
2017/05/20 Javascript
jq源码解析之绑在$,jQuery上面的方法(实例讲解)
2017/10/13 jQuery
video.js 一个页面同时播放多个视频的实例代码
2018/11/27 Javascript
Node.js中console.log()输出彩色字体的方法示例
2019/12/01 Javascript
JavaScript中条件语句的优化技巧总结
2020/12/04 Javascript
[03:41]DOTA2上海特锦赛小组赛第三日recap精彩回顾
2016/02/28 DOTA
关于python的list相关知识(推荐)
2017/08/30 Python
简述Python2与Python3的不同点
2018/01/21 Python
pygame实现俄罗斯方块游戏
2018/06/26 Python
python3.6使用urllib完成下载的实例
2018/12/19 Python
使用Python的SymPy库解决数学运算问题的方法
2019/03/27 Python
django echarts饼图数据动态加载的实例
2019/08/12 Python
CSS3图片旋转特效(360/60/-360度)
2013/10/10 HTML / CSS
HTML5轻松实现全屏视频背景的示例
2018/04/23 HTML / CSS
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
金蝶的一道SQL笔试题
2012/12/18 面试题
办公室文员工作自我评价
2013/12/01 职场文书
校庆接待方案
2014/03/18 职场文书
导师评语大全
2014/04/26 职场文书
档案信息化建设方案
2014/05/16 职场文书
小学假期安全广播稿
2014/09/28 职场文书
终止劳动合同通知书
2015/04/16 职场文书
2016年优秀共产党员先进事迹材料
2016/02/29 职场文书
Nginx报404错误的详细解决方法
2022/07/23 Servers