PHP设计模式之单例模式(数据库访问)

时间:2021-10-29 10:03:18

1.什么是单例模式?

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。

 

2.单例模式的三个要点

A.需要一个保存类的唯一实例的静态成员变量:

private static $_instance;

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

private function __construct()   
{
}

private function __clone()  
{  
}

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

public static function getInstance(){

    if (!(self::$_instance instanceof self)) {
        self::$_instance = new self();
    }
    return self::$_instance;
}

 

3.为什么要使用单例模式?

A.PHP缺点:

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

B.单例模式在PHP中的应用场合:

一个应用中会存在大量的数据库操作,比如过数据库句柄来连接数据库这一行为,使用单例模式可以避免大量的new操作,因为每一次new操作都会消耗内存资源和系统资源。

 

4.应用单例模式对数据库进行操作

/**
 * 设计模式之单例模式(单例模式生成一个对象后,此对象可以被众多其它对象所使用)
 * 使用场景:最常用的地方是数据库连接。
 *
 * $_instance 必须声明为 私有的静态变量
 * 构造函数和析构函数 必须声明为 私有的,防止外部程序new类,从而失去单例模式的意义(减少内存消耗)
 * getInstance()方法必须声明为 公有的,必须调用此方法,以返回实例的一个引用
 *
 * 知识:1.双冒号操作符(::)只能访问静态变量和静态函数;2.new实例化对象都会消耗内存
 */
class db {

    private $conn;

    /**
     * 1.静态变量(static),保存全局实例
     * 2.私有属性(private),为了避免类外直接 new实例化 调用
     */
    private static $sql;
    private static $_instance;

    /** 私有化构造函数,防止外界实例化对象 **/
    private function __construct(){

        require_once('db.config.php');
        $this->conn = mysql_connect($conf['host'], $conf['user'], $conf['password']) OR die(mysql_error());
        mysql_select_db($conf['database'], $this->conn) OR die(mysql_error());

        mysql_query('SET NAMES '.$conf['charset'].';', $this->conn);
    }

    /** 静态方法,单例访问统一入口 **/
    public static function getInstance(){

        if (!(self::$_instance instanceof self)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /** 私有化克隆函数,防止外界克隆对象 **/
    private function __clone(){}

    /** 解析条件语句 **/
    private function _parseCondition($condition){

        if(is_array($condition)){
            $where = '';
            foreach($condition as $k => $v){
                $where.= "AND `".$k."` = '".$v."' ";
            }
            $where = '('.trim(ltrim($where, 'AND')).')';
        }else{
            $where = $condition;
        }
        return $where;
    }

    /** 解析字段语句 **/
    private function _parseFields($fields){

        if(is_array($fields)){
            $field = '';
            foreach($fields as $rs){
                $field .= ', `'.$rs.'`';
            }
            $field = trim(ltrim($field, ','));
        }else{
            $field = $fields;
        }
        return $field;
    }

    /** 查询数据库 **/
    public function select($table, $condition = array(), $field = array()){

        $where = empty($condition) ? '' : ' WHERE '.$this->_parseCondition($condition);
        $fields = empty($field) ? '*' : $this->_parseFields($field);

        self::$sql = 'SELECT '.$fields.' FROM '.$table.$where;

        $query = mysql_query(self::$sql, $this->conn);
        $ary = array();
        while($row = mysql_fetch_array($query, MYSQL_ASSOC)){
            $ary[] = $row;
        }
        return $ary;
    }

    /** 返回当前SQL语句 **/
    public function getLastSql(){
        return self::$sql;
    }
}

 

5.测试代码

header('Content-Type:text/html; Charset=utf-8;');
$db = db::getInstance();
$list = $db->select('table', array(), array());
echo $db->getLastSql();
echo '<pre>';
print_r($list);
echo '</pre>';

注意:记得配置db.config.php的数据库数组值