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 相关文章推荐
PHPLog php 程序调试追踪工具
Sep 09 PHP
劣质的PHP代码简化
Feb 08 PHP
PHP 引用是个坏习惯
Mar 12 PHP
php面向对象 字段的声明与使用
Jun 14 PHP
Yii Framework框架获取分类下面的所有子类方法
Jun 20 PHP
PHP实现获取图片颜色值的方法
Jul 11 PHP
PHP通过内置函数memory_get_usage()获取内存使用情况
Nov 20 PHP
php对象在内存中的存在形式分析
Feb 03 PHP
php实现通过ftp上传文件
Jun 19 PHP
thinkPHP中分页用法实例分析
Dec 26 PHP
微信公众平台DEMO(PHP)
May 04 PHP
php用wangeditor3实现图片上传功能
Aug 22 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 图像处理类1
2009/06/15 PHP
有关JSON以及JSON在PHP中的应用
2010/04/09 PHP
PHP中单引号与双引号的区别分析
2014/08/19 PHP
ThinkPHP 404页面的设置方法
2015/01/14 PHP
Thinkphp关闭缓存的方法
2015/06/26 PHP
php生成图片验证码-附五种验证码
2015/08/19 PHP
微信支付开发动态链接Native支付
2016/07/12 PHP
magento后台无法登录解决办法的两种方法
2016/12/09 PHP
PHP goto语句用法实例
2019/08/06 PHP
jquery仿京东导航/仿淘宝商城左侧分类导航下拉菜单效果
2013/04/24 Javascript
15款jQuery分布引导插件分享
2015/02/04 Javascript
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现
2015/03/05 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
2016/01/28 Javascript
JavaScript的ExtJS框架中表格的编写教程
2016/05/21 Javascript
jquery动态添加文本并获取值的方法
2016/10/12 Javascript
Angular-Touch库用法示例
2016/12/22 Javascript
详解Vue-cli代理解决跨域问题
2017/09/27 Javascript
vue.js中引入vuex储存接口数据及调用的详细流程
2017/12/14 Javascript
小程序扫描普通链接二维码跳转小程序指定界面方法
2019/05/07 Javascript
js实现表格数据搜索
2020/08/09 Javascript
解决nuxt 自定义全局方法,全局属性,全局变量的问题
2020/11/05 Javascript
Python实现线程池代码分享
2015/06/21 Python
Python实现一个转存纯真IP数据库的脚本分享
2017/05/21 Python
使用Eclipse如何开发python脚本
2018/04/11 Python
详解python使用pip安装第三方库(工具包)速度慢、超时、失败的解决方案
2018/12/02 Python
如何将tensorflow训练好的模型移植到Android (MNIST手写数字识别)
2020/04/22 Python
Python爬虫如何破解JS加密的Cookie
2020/11/19 Python
中医专业应届生求职信
2013/11/17 职场文书
银行求职自荐信
2014/06/30 职场文书
行政求职信
2014/07/04 职场文书
本科毕业论文指导教师评语
2014/12/30 职场文书
街道办残联2016年助残日活动总结
2016/04/01 职场文书
Javascript中的解构赋值语法详解
2021/04/02 Javascript
alibaba seata服务端具体实现
2022/02/24 Java/Android