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正则
Jul 07 PHP
PHP 网页过期时间的控制代码
Jun 29 PHP
PHP函数学习之PHP函数点评
Jul 05 PHP
php中隐形字符65279(utf-8的BOM头)问题
Aug 16 PHP
php获取QQ头像并显示的方法
Dec 23 PHP
php提交过来的数据生成为txt文件
Apr 28 PHP
php中时间函数date及常用的时间计算
May 12 PHP
实例讲解PHP页面静态化
Feb 05 PHP
thinkPHP中U方法加密传递参数功能示例
May 29 PHP
PHP操作Redis数据库常用方法示例
Aug 25 PHP
关于PHP中interface的用处详解
Jul 26 PHP
PHP配置文件php.ini中打开错误报告的设置方法
Jan 09 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 pcntl_fork和pcntl_fork 的用法
2009/04/13 PHP
PHP5中使用PDO连接数据库的方法
2010/08/01 PHP
PHP学习笔记 IIS7下安装配置php环境
2012/10/29 PHP
php 字符串中是否包含指定字符串的多种方法
2018/04/12 PHP
jquery插件jbox使用iframe关闭问题
2009/02/09 Javascript
HTML node相关的一些资料整理
2010/01/01 Javascript
jQuery-ui中自动完成实现方法
2010/06/10 Javascript
我的javascript 函数链之演变
2011/04/07 Javascript
JavaSciprt中处理字符串之sup()方法的使用教程
2015/06/08 Javascript
js针对ip地址、子网掩码、网关的逻辑性判断
2016/01/06 Javascript
JavaScript设计模式之单体模式全面解析
2016/09/09 Javascript
Webpack path与publicPath的区别详解
2018/05/03 Javascript
Layui点击图片弹框预览的实现方法
2019/09/16 Javascript
vue设置默认首页的操作
2020/08/12 Javascript
python通过scapy获取局域网所有主机mac地址示例
2014/05/04 Python
python3编写C/S网络程序实例教程
2014/08/25 Python
python通过索引遍历列表的方法
2015/05/04 Python
Python中线程编程之threading模块的使用详解
2015/06/23 Python
在DigitalOcean的服务器上部署flaskblog应用
2015/12/19 Python
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
2018/03/22 Python
python hashlib加密实现代码
2019/10/17 Python
Python类继承和多态原理解析
2020/02/05 Python
Python实现遗传算法(二进制编码)求函数最优值方式
2020/02/11 Python
Python通过4种方式实现进程数据通信
2020/03/12 Python
python中pop()函数的语法与实例
2020/12/01 Python
大学专科生推荐信范文
2013/11/23 职场文书
学校火灾防控方案
2014/06/09 职场文书
四查四看整改措施
2014/09/19 职场文书
教师党员自我评价2015
2015/03/04 职场文书
2015年全国科普日活动总结
2015/03/23 职场文书
涨价通知怎么写
2015/04/23 职场文书
小学运动会加油词
2015/07/18 职场文书
62句有关感恩节文案(推荐收藏)
2019/11/28 职场文书
详解MongoDB的条件查询和排序
2021/06/23 MongoDB
一次Mysql update sql不当引起的生产故障记录
2022/04/01 MySQL
Nginx配置根据url参数重定向
2022/04/11 Servers