PHP单例模式(精讲)

Wesley13
• 阅读 820

首先我们要明确单例模式这个概念,那么什么是单例模式呢?

单例模式顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类我们称之为单例类。

单例模式的要点有三个:

一是某个类只能有一个实例;

二是它必须自行创建这个实例;

三是它必须自行向整个系统提供这个实例。

<?php
/* 单例模式举例,其要点如下:
 *
 * 1. $_instance 必须声明为静态的私有变量
 * 2. 构造函数和克隆函数必须声明为私有的,这是为了防止外部程序 new 类从而失去单例模式的意义
 * 3. getInstance()方法必须声明为公有的,必须调用此方法以返回唯一实例的一个引用
 * 4. ::操作符只能访问静态变量或静态函数
 * 5. PHP的单例模式是相对而言的,因为PHP的解释运行机制使得每个PHP页面被解释执行后,所有的相关资源都会被回收。
 * 也就是说,PHP在语言级别上没有办法让某个对象常驻内存。在PHP中,所有的变量都是页面级的,无论是全局变量,
 * 还是类的静态成员,都会在页面执行完毕后被清空,结果会重新建立新的对象,这样也就完全失去了Singleton的意义。
 * 不过,在实际应用中同一个页面中可能会存在多个业务逻辑,这时单例模式就起到了很重要的作用,有效的避免了重复
 * new 对象(注: new 对象会消耗内存资源)这么一个行为,所以我们说PHP的单例模式是相对而言的
 *
*/
class People {
    static private $_instance = NULL;
    public $height = '';
    public $age = '';
    private function __construct() {
        $this->height = '185';
        $this->age = 25;
    }
    private function __clone() {
        //do something
        
    }
    static public function getInstance() {
        if (!self::$_instance instanceof self) {
            //echo 'lgh-big';
            self::$_instance = new self;
        } else {
            //for testing only
            //echo 'gdc-xiaoairener';
            
        }
        return self::$_instance;
    }
    public function getHeight() {
        echo $this->height;
    }
    public function getAge() {
        echo $this->age;
    }
}
function testInstance() {
    People::getInstance()->getAge();
}
//begin to use the class
$lgh = People::getInstance();
$lgh->getHeight();
echo '<br />';
testInstance();
?>

下面我们讨论下为什么要使用PHP单例模式?

多数人都是从单例模式的字面上的意思来理解它的用途, 认为这是对系统资源的节省, 可以避免重复实例化, 是一种"计划生育"。而PHP每次执行完页面都是会从内存中清理掉所有的资源。因而PHP中的单例实际每次运行都是需要重新实例化的,这样就失去了单例重复实例化的意义了。单单从这个方面来说,PHP的单例的确有点让各位失望。但是单例仅仅只有这个功能和应用吗?答案是否定的,我们一起来看看。

1. php的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作,在使用面向对象的方式开发时,如果使用单例模式,则可以避免大量的new 操作消耗的资源。

2. 如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。这个可以参看zend Framework的FrontController部分。

3. 在一次页面请求中,便于进行调试,因为所有的代码(例如数据库操作类db)都集中在一个类中,我们可以在类中设置钩子,输出日志,从而避免到处var_dump, echo。

使用传统方式编码

<?php
//初始化一个数据库句柄
$db = new DB();
//比如有个应用场景是添加一条用户信息:
$db->addUserInfo();
//然而我们在另外一个地方可能要查找用户的信息,这个情景出现在一个函数中,这时要用到数据库句柄资源,我们可能需要这么去做
function test() {
    //这时我们不得不重新初始化一个数据库句柄,试想多个应用场景下,这样的代码是多么可怕啊?!
    $db = new DB();
    $db->getUserInfo();
    //有些朋友或许会说,我也可以不这样做啊,我直接利用global关键字不就可以了吗?的确,global可以解决问题,也起到了单例模式的作用,但是OOP中,我们拒绝这样来编写代码,因为global存在安全隐患,请参考相关书籍,同时单例模式恰恰是对全局变量的一种改进,避免了那些存储唯一实例的全局变量污染命名空间
    global $db; //OOP中,我们不提倡这样编写代码
}

使用单例模式编码

<?php
//所有的应用情景只有一个数据库句柄资源,嘿嘿,效率老高了,
//资源也大大的得到节省,代码简洁明了:)
DB::getInstance()->addUserInfo();
DB::getInstance()->getUserInfo(); 

PHP单例模式实现的核心要点有如下三条:

1.需要一个保存类的唯一实例的静态成员变量(通常为$_instance私有变量)

2.构造函数和克隆函数必须声明为私有的,这是为了防止外部程序new类从而失去单例模式的意义

3.必须提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一实例的一个引用

在了解了单例模式的应用场景之后,下面我们通过编写单例模式的具体实现代码来掌握PHP单例模式的核心要点,代码如下:

<?php
/**
 *  PHP单例模式演示举例
 *  @author   guohua.li
 *  @modify  2010-07-11
 *  @website  http://blog.163.com/lgh_2002/
 */
class User {
    /**
     *  静态成品变量 保存全局实例
     *  @access private
     */
    static private $_instance = NULL;
    /**
     *  私有化构造函数,防止外界实例化对象
     */
    private function __construct() {
    }
    /**
     *  私有化克隆函数,防止外界克隆对象
     */
    private function __clone() {
    }
    /**
     *  静态方法, 单例统一访问入口
     *  @return  object  返回对象的唯一实例
     */
    static public function getInstance() {
        if (is_null(self::$_instance) || !isset(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    /**
     * 测试方法: 获取用户名字
     */
    public function getName() {
        echo 'hello liguohua!';
    }
}

PHP单例模式的缺点

众所周知,PHP语言是一种解释型的脚本语言,这种运行机制使得每个PHP页面被解释执行后,所有的相关资源都会被回收。也就是说,PHP在语言级别上没有办法让某个对象常驻内存,这和asp.net、Java等编译型是不同的,比如在Java中单例会一直存在于整个应用程序的生命周期里,变量是跨页面级的,真正可以做到这个实例在应用程序生命周期中的唯一性。然而在PHP中,所有的变量无论是全局变量还是类的静态成员,都是页面级的,每次页面被执行时,都会重新建立新的对象,都会在页面执行完毕后被清空,这样似乎PHP单例模式就没有什么意义了,所以PHP单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的。

参考链接:

http://www.cnblogs.com/zox2011/archive/2011/09/20/2182119.html

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java设计模式1
1:单例模式简介  单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例。总而言之就是在系统中只会存在一个对象,其中的数据是共享的  特点:    单例类只能有一个实例,所以一般会用static进行修释。    单例类必须自己创建自己的唯一实例。也就是在类中要new一个自己。    单例类必
Wesley13 Wesley13
3年前
java 23种设计模式(五、单例模式)
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例模式的结构  单例模式的特点:单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。  饿汉式单例类publicclassEagerSingleton
红烧土豆泥 红烧土豆泥
3年前
创建型模式之单例设计模式
什么是单例设计模式?顾名思义,只有一个实例。单例模式它主要是确保一个类只有一个实例,并且可以提供一个全局的访问点。废话少说,直接上干货了单例模式之饿汉式所谓饿汉式,顾名思义,“它很饿”。所以说,它一旦被加载进来,就会直接实例化一个对象。例如:languageclassSingleton{privatestaticfin
Wesley13 Wesley13
3年前
PHP单例模式
<?php/设计模式之单例模式$_instance必须声明为静态的私有变量构造函数和析构函数必须声明为私有,防止外部程序new类从而失去单例模式的意义getInstance()方法必须设置为公有的,必须调用此方法以返回实例的一个引
Wesley13 Wesley13
3年前
JAVA设计模式之单例设计模式
    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。  在JAVA中实现单例,必须了解JAVA内存机制,JAVA中实例对象存在于堆内存中,若要实现单例,必须满足两个条件:  1.限制类实例化对象。即只能产生一个对象。
Wesley13 Wesley13
3年前
Java单例模式
什么是单例模式  单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。为什么要用单例模式节省内存节省计算如对象实例中的一样的,那就不用每次都创建一个对象方便管理因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
Wesley13 Wesley13
3年前
(面试常问)4种单例设计模式的总结(内含代码以及分析)
单例设计模式:  单例模式,是一种常见的软件设计模式.在它的核心结构中只包含了一个被称为单例的特殊类.通过单例模式可以保证系统中只有该类的一个实例对象.优点:  实例控制:单例模式会阻止其它对象实例化其自己的单例对象的副本,从而确保所有对象都访问的是唯一的实例   灵活性:因为类控制了实例化过程,所以类可以很灵活的更改实
Stella981 Stella981
3年前
C#设计模式(1)——单例模式(Singleton)
单例模式即所谓的一个类只能有一个实例,也就是类只能在内部实例一次,然后提供这一实例,外部无法对此类实例化。单例模式的特点:1、只能有一个实例;2、只能自己创建自己的唯一实例;3、必须给所有其他的对象提供这一实例。普通单例模式(没有考虑线程安全)  ///<summary///单例模式
Wesley13 Wesley13
3年前
Java设计模式:Singleton(单例)模式
概念定义Singleton(单例)模式是指在程序运行期间,某些类只实例化一次,创建一个全局唯一对象。因此,单例类只能有一个实例,且必须自己创建自己的这个唯一实例,并对外提供访问该实例的方式。单例模式主要是为了避免创建多个实例造成的资源浪费,以及多个实例多次调用容易导致结果出现不一致等问题。例如,一个系统只能有一个窗口管理器或文件系统,一个程
Wesley13 Wesley13
3年前
23种设计模式(1):单例模式
定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。类型:创建类模式类图:!23种设计模式(1):单例模式第1张|快课网(http://static.oschina.net/uploads/img/201407/05200605_0dij.gif"23种设计模式(1):单例模式