PHP单例模式总结教程

相关文章:析php单态设计模式之单例模式的理解

相关文章:php设计模式——单例模式(Singleton)的常见应用场景<

 

单例模式,就是保持一个对象只存在一个实例。并且为该唯一实例提供一个全局访问点(一般是一个静态的getInstance方法)。单例模式应用场景非常广泛,例如:

数据库操作对象
日志写入对象
全局配置解析对象等

这些场景的共同特征是从业务逻辑上来看运行期间改对象却是只需要一个实例、不断new多个实例会增加不必要的资源消耗、全局调用便利。下面分别说明这三个方面:

1. 业务上只需要一个实例

以数据库连接对象为例,加入有一个购物网站,有一个MySQL数据库 127.0.0.1:3306, 那么在一个进程中无论我们需要进行多少次针对改数据库的操作,都只需要连接数据库一次,使用相同的数据库连接句柄(MySQL Connection Resource),从业务需求上来看就只需要一个实例。

相反,同样以购物网站为例,存在许多商品,这些商品都不一样(id,name,price..),这个时候需要显示一个商品列表,加入我们建立一个 Product 作为数据映射对象,那么从业务需求上来说,一个实例就无法满足业务需求,因为每个商品都不一样。

2. 不断new操作增加不必要的资源消耗

我们一般会在类的构造方法(new操作肯定会调用)中进行一些业务操作,例如数据库连接对象可能会在构造方法中尝试读取数据库配置并进行数据库连接(如mysqli::__construct())、日志写入对象会判断日志写入目录是否存在并写入(不存在可能尝试创建改目录)、全局配置解析对象可能需要定位配置文件的保存目录并进行文件扫描等。

这些业务都会消耗相当的资源,如果在一个进程中我们值需要做一次,将会非常有利于我们提高应用的运行效率。

3. 全局调用便利

因为单例模式的一大特点就是通过静态方法获取对象实例,那么就意味着访问对象的方法时不需要先new一个对象的实例,如果改对象需要很多地方使用,则提高了调用的便利性。

通过一个日志操作类来举例:

 代码如下 复制代码

class Logger{

    //首先,需要一个私有的静态变量来存储产生的对象实例
    private static $instance;

    //业务变量,保存日志写入路径
    private $logDir;

    //构造方法,注意必须也是私有的,不允许被外部实例化(即在外部被new)
    private function __construct(){
        //调试输出,测试对象被new的次数
        echo "new Logger instance rn";
        $logDir = sys_get_temp_dir(). DIRECTORY_SEPARATOR . "logs";
        if(!is_dir($logDir) || !file_exists($logDir)){
            @mkdir($logDir);
        }
        $this->logDir = $logDir;

    }

    //类唯一实例的全局访问点,用于判断并返回对象实例,供外部调用
    public static function getInstance(){
        if(is_null(self::$instance)){
            $class = __CLASS__; //获取本对象的类型,也可以用new self()方式
            self::$instance = new $class();
        }
        return self::$instance;
    }

    //重载__clone()方法,不允许对象对克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }

    //具体的业务方法,实际可以有很多方法
    public function logError($message){
        $logFile = $this->logDir . DIRECTORY_SEPARATOR . "error.log";
        error_log($message, 3, $logFile);
    }
}

//日志调用
$logger = Logger::getInstance();
$logger->logError("An error occured");
$logger->logError("Another error occured");

//或者这样调用
Logger::getInstance()->logError("Still have error");
Logger::getInstance()->logError("I should fix it");

在单例模式中可能遇到一种比较特殊的情况,比如数据库连接对象,对于大型应用来说,很可能需要连接多台数据库,那么不同的数据库公用一个对象可能会产生问题,比如连接的分配、获取insert_id,last_error等。这个问题也比较好解决,就是把我们的$instance变量变成一个关联数组,通过给getInstance方法传入不同的参数获取不同的"单例对象"(引号的含义是:严格来说类可能被new多次,但是这个new也是在我们的控制之内的,而不是在类外部):

 代码如下 复制代码

class MysqlServer{
    //注意,变成复数了哦^_^  当然只是为了标识而已
    private static $instances = array();

    //业务变量,保持当前实例的mysqli对象
    private $conn;

    //显著特征:私有的构造方法,避免在类外部被实例化
    private function __construct($host, $username, $password, $dbname, $port){
        $this->conn = new mysqli($host, $username, $password, $dbname, $port);
    }

    //类唯一实例的全局访问点
    public static function getInstance($host='localhost', $username='root', $password='123456', $dbname='mydb', $port='3306'){
        $key = "{$host}:{$port}:{$username}:{$dbname}";
        if (empty(self::$instances[$key])){
            //这里也可以用 new self(); 的方式
            $class = __CLASS__;
            self::$instances[$key] = new $class($host, $username, $password, $dbname, $port);
        }
        return self::$instances[$key];
    }

    //重载__clone方法,不允许对象实例被克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }

    //查询业务方法,后面省略其它业务方法
    public function query($sql){
        return $this->conn->query($sql);
    }

    //尽早释放资源
    public function __destruct(){
        $this->conn->close();
    }
}

问题1:单例类能否拥有子类,因为单例类的构造方法是私有的,因此无法被继承,如果要继承则需要将构造方法改为protected或public,这就违背了单例模式的本意。因此,如果你想给单例类加子类,那就需要回头想想是否错用了模式,或者结构设计上有问题。

问题2:单例滥用,单例模式相对来说比较好理解和实现,因此一旦认识到单例模式的好处,很可能什么类都想写成单例,因此在使用次模式之前一定要考虑上述3种情况,看是否真的有必要使用。

 

时间: 2024-10-13 11:57:55

PHP单例模式总结教程的相关文章

C# 设计模式系列教程-单例模式_C#教程

1. 描述: 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 2. 单例模式主要有3个特点,: 2.1 单例类确保自己只有一个实例. 2.2 单例类必须自己创建自己的实例. 2.3 单例类必须为其他对象提供唯一的实例. 3. 实现方式:懒汉单例类和饿汉单例类 3.1 懒汉式单例类 对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备.它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,然后返回,如果已有对象就不再创建,立即返

PHP单例模式实现商城购物车功能-PHP实例教程

  PHP单例模式实现商城购物车功能-PHP实例教程完成这个小功能必须会写需求 养成好的习惯 Php购物车的开发需求功能如下 1: 购物车放在session里 2: 单例模式来开发 功能: 增删改查 增一个商品 减少 PHP单例模式实现商城购物车功能-PHP实例教程完成这个小功能必须会写需求 养成好的习惯 Php购物车的开发需求功能如下:php100.com 1: 购物车放在session里 2: 单例模式来开发 功能: 增删改查 增一个商品 减少一个商品(改,数量) 删 去掉一个商品 清空购物

c#单例模式(Singleton)的6种实现_C#教程

1.1.1 摘要  在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是我们今天要介绍的--单例模式(Singleton).  使用频率高 单件模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点. 1.1.2 正文 图1单例模式(Singleton)结构图 单例模式(Singleton)是几个创建模式中最对立的一个,它的主要特点不是根据

C# 2.0教程专题

Visual C# 2010新特性之dynamic类型 Visual C# 2010新特性之命名和可选参数与类型等价支持 C# 2.0教程专题 用Visual C# 2005创建快捷方式 用VC#2005解析含有多种格式的文本文件 利用VC# 2005为数码照片添加拍照日期 VC#2005快速入门之使用布尔操作符 VC#2005快速入门之使用while语句 Effective C#原则49:为C#2.0做好准备 VC#2005快速入门之使用if语句 VC#2005快速入门之使用do语句 VC#2

PHP基于单例模式实现的mysql类_php技巧

本文实例讲述了PHP基于单例模式实现的mysql类.分享给大家供大家参考,具体如下: <?php defined('ACC')||exit('Access Denied'); // 封装mysql操作类,包括连接功能,及查询功能. class mysql extends absdb{ protected static $ins = null; protected $host; // 主机名 protected $user; // 用户名 protected $passwd; // 密码 prot

cocos2d-x设计模式发掘之一:单例模式

      作者: firedragonpzy  原地址:http://www.firedragonpzy.com.cn/index.php/archives/1781      本系列文章我将和大家一起来发掘cocos2d-x中所使用到的设计模式,同样的,这些模式在cocos2d-iphone中也可以找到其身影.      声明:这里发掘模式只是我的个人爱好,通过这个过程,我希望能加深自己对于设计模式运用的理解.关于模式的学习,市面上已经有许多非常好的书籍了.比如<HeadFirst设计模

给 Java 学习者的超全教程整理

Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系统.完整.可学性较强的教程其实并不是那么容易.实验楼上有很多 Java 教程,从基础入门.J2SE 开发.SSH 框架到实战项目都有,因此,这里就把这些课程总结一下,希望对 Java 学习者有所帮助~ 一.Java基础 Java 基础不必多说了,下面的5门课程就可以带你动手学习,入门Java. Ja

PHP设计模式之工厂模式与单例模式_php技巧

本文实例讲述了PHP设计模式之工厂模式与单例模式实现方法.分享给大家供大家参考,具体如下: 设计模式简单说应对某类问题而设计的解决方式 工厂模式:应对需求创建相应的对象 class factory{ function __construct($name){ if(file_exists('./'.$name.'.class.php')){ return new $name; }else{ die('not exist'); } } } 单例模式:只创建一个对象的实例,不允许再创建实例,节约资源(

Zend Framework教程之前端控制器Zend_Controller_Front用法详解_php实例

本文实例讲述了Zend Framework教程之前端控制器Zend_Controller_Front用法.分享给大家供大家参考,具体如下: 主要功能 ZendFramework的MVC实现的核心机制是通过Zend_Controller_Front前端控制器,用于初始化请求环境,处理请求,路由分发,完成响应操作,Zend_Controller_Front采用的单例模式,所以一个应用只有一个前端控制器.如果需要前端控制器提供一些特殊功能,可以继承Zend_Controller_Front自定义前端控