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桌面中心(四) 数据显示
Mar 11 PHP
使用 MySQL Date/Time 类型
Mar 26 PHP
php下通过POST还是GET来传值
Jun 05 PHP
Views rows style模板重写代码
May 16 PHP
php设计模式 Builder(建造者模式)
Jun 26 PHP
析构函数与php的垃圾回收机制详解
Oct 28 PHP
PHP动态编译出现Cannot find autoconf的解决方法
Nov 05 PHP
浅谈PHP命令执行php文件需要注意的问题
Dec 16 PHP
解决PHP 7编译安装错误:cannot stat ‘phar.phar’: No such file or directory
Feb 25 PHP
PHP文件类型检查及fileinfo模块安装使用详解
May 09 PHP
php简单计算权重的方法示例【适合抽奖类应用】
Jun 10 PHP
如何在PHP中生成随机数
Jun 04 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整合七牛实现上传文件
2015/07/03 PHP
PHP中关键字interface和implements详解
2017/06/14 PHP
js 优化次数过多的循环 考虑到性能问题
2011/03/05 Javascript
javascript根据时间生成m位随机数最大13位
2014/10/30 Javascript
Javascript基于对象三大特性(封装性、继承性、多态性)
2016/01/04 Javascript
javascript先序遍历DOM树的方法
2016/02/27 Javascript
AngularJS入门教程之静态模板详解
2016/08/18 Javascript
bootstrap多种样式进度条展示
2016/12/20 Javascript
解决webpack -p压缩打包react报语法错误的方法
2017/07/03 Javascript
详解基于mpvue的小程序markdown适配解决方案
2018/05/08 Javascript
nodeJS服务器的创建和重新启动的实现方法
2018/05/12 NodeJs
vue实现底部菜单功能
2018/07/24 Javascript
js console.log打印对象时属性缺失的解决方法
2019/05/23 Javascript
[03:48]显微镜下的DOTA2第四期——TP动作
2014/06/20 DOTA
[01:03:27]Optic vs VGJ.S 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
Python中isnumeric()方法的使用简介
2015/05/19 Python
PYTHON压平嵌套列表的简单实现
2016/06/08 Python
Python函数装饰器实现方法详解
2018/12/22 Python
Python 保存矩阵为Excel的实现方法
2019/01/28 Python
python3.x提取中文的正则表达式示例代码
2019/07/23 Python
如何在python中执行另一个py文件
2020/04/30 Python
python 爬虫如何正确的使用cookie
2020/10/27 Python
SKECHERS斯凯奇中国官网:来自美国的运动休闲品牌
2018/11/14 全球购物
英国护发和美妆在线商店:Klip Shop
2019/03/24 全球购物
BSTN意大利:德国街头和运动文化高品质商店
2020/12/22 全球购物
课堂教学改革实施方案
2014/03/17 职场文书
《果园机器人》教学反思
2014/04/13 职场文书
考试没考好检讨书(精选篇)
2014/11/16 职场文书
2015年电工工作总结
2015/04/10 职场文书
班主任远程培训研修日志
2015/11/13 职场文书
2016年入党心得体会范文
2016/01/23 职场文书
2016年基层党支部书记公开承诺书
2016/03/25 职场文书
网络安全倡议书(3篇)
2019/09/18 职场文书
python实现A*寻路算法
2021/06/13 Python
分布式Redis Cluster集群搭建与Redis基本用法
2022/02/24 Redis
灵能百分百第三季什么时候来?
2022/03/15 日漫