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 相关文章推荐
PHP4实际应用经验篇(8)
Oct 09 PHP
php如何调用webservice应用介绍
Nov 24 PHP
解析php入库和出库
Jun 25 PHP
php查找任何页面上的所有链接的方法
Dec 03 PHP
php fsockopen解决办法 php实现多线程
Jan 20 PHP
PHP判断文章里是否有图片的简单方法
Jul 26 PHP
php在数据库抽象层简单使用PDO的方法
Nov 03 PHP
smarty模板数学运算示例
Dec 11 PHP
利用PHP生成CSV文件简单示例
Dec 21 PHP
php用xpath解析html的代码实例讲解
Feb 14 PHP
浅谈laravel-admin form中的数据,在提交后,保存前,获取并进行编辑
Oct 21 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
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
星际中的相关伤害
2020/03/04 星际争霸
针对初学PHP者的疑难问答(2)
2006/10/09 PHP
实例(Smarty+FCKeditor新闻系统)
2007/01/02 PHP
PHP定时执行计划任务的多种方法小结
2011/12/19 PHP
php模板函数 正则实现代码
2012/10/15 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
2014/08/19 PHP
PHP结合Ffmpeg快速搭建流媒体服务的实践记录
2018/10/31 PHP
Extjs4 Treegrid 使用心得分享(经验篇)
2013/07/01 Javascript
7个JS基础知识总结
2014/03/05 Javascript
AngularJS入门心得之directive和controller通信过程
2016/01/25 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
nodejs搭建本地服务器并访问文件的方法
2017/03/03 NodeJs
浅谈webpack+react多页面开发终极架构
2018/11/11 Javascript
webpack4.x下babel的安装、配置及使用详解
2019/03/07 Javascript
js常见遍历操作小结
2019/06/06 Javascript
详解Vue中CSS样式穿透问题
2019/09/12 Javascript
AngularJS动态生成select下拉框的方法实例
2019/11/17 Javascript
[44:47]Ti4 循环赛第三日 iG vs NaVi
2014/07/12 DOTA
在Python中使用__slots__方法的详细教程
2015/04/28 Python
Python判断直线和矩形是否相交的方法
2015/07/14 Python
Python中矩阵库Numpy基本操作详解
2017/11/21 Python
浅谈Python使用Bottle来提供一个简单的web服务
2017/12/27 Python
Python字典中的键映射多个值的方法(列表或者集合)
2018/10/17 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
django2.2 和 PyMySQL版本兼容问题
2020/02/17 Python
python 实现图像快速替换某种颜色
2020/06/04 Python
德国购买健身器材:AsVIVA
2017/08/09 全球购物
英国最大的网上药品商店:Chemist Direct
2017/12/16 全球购物
深入开展党的群众路线教育实践活动方案
2014/02/04 职场文书
开学第一周总结
2015/07/16 职场文书
领导莅临指导欢迎词
2015/09/30 职场文书
Django中session进行权限管理的使用
2021/07/09 Python
SQL实现LeetCode(196.删除重复邮箱)
2021/08/07 MySQL
正则表达式拆分url实例代码
2022/02/24 Java/Android
详解python的异常捕获
2022/03/03 Python