当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP 单例模式优点意义及如何实现

发布:smiling 来源: PHP粉丝网  添加日期:2018-10-28 20:43:38 浏览: 评论:0 

一、什么是单例模式?

1、含义   

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

2、单例模式的三个要点:

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

private static $_instance; 

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

  1. private function __construct(){    
  2.     $this->_db = pg_connect('xxxx');   
  3. }    
  4. private function __clone()   
  5. {   
  6. }//覆盖__clone()方法,禁止克隆  

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

  1. public static function getInstance(){     
  2.     if(! (self::$_instance instanceof self) )    
  3.     {     
  4.         self::$_instance = new self();     
  5.     }   
  6.     return self::$_instance; 
  7. }    
二、为什么要使用单例模式?

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

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

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

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

1、PHP缺点:

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

2、单例模式在PHP中的应用场合:

(1)、应用程序与数据库交互

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

(2)、控制配置信息

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

三、如何实现单例模式?

1、普通的数据库访问例子:

  1. <?php   
  2. ......   
  3. //初始化一个数据库句柄   
  4. $db = new DB(...);   
  5.     
  6. //添加用户信息   
  7. $db->addUserInfo(...);   
  8.     
  9. ......   
  10.     
  11. //在函数中访问数据库,查找用户信息   
  12. function getUserInfo()   
  13. {   
  14.     $db = new DB(...);//再次new 数据库类,和数据库建立连接   
  15.     $db = query(....);//根据查询语句访问数据库   
  16. }   
  17.     
  18. ?> 

2、应用单例模式对数据库进行操作:

  1. <?php  
  2. class DB     
  3. {     
  4.     private $_db;     
  5.     private static $_instance;     
  6.       
  7.     private function __construct(...)     
  8.     {     
  9.         $this->_db = pg_connect(...);//postgrsql     
  10.     }     
  11.       
  12.     private function __clone() {};  //覆盖__clone()方法,禁止克隆     
  13.       
  14.     public static function getInstance()     
  15.     {     
  16.         if(! (self::$_instance instanceof self) ) {     
  17.             self::$_instance = new self();     
  18.         }     
  19.         return self::$_instance;     
  20.     }     
  21.       
  22.     public function addUserInfo(...)   
  23.     {   
  24.     }   
  25.      public function getUserInfo(...)   
  26.     {   //phpfensi.com 
  27.     }   
  28.     
  29. }   
  30.     
  31. //test     
  32. $db = DB::getInstance();     
  33. $db->addUserInfo(...);     
  34. $db->getUserInfo(...);    
  35.     
  36. ?> 

下面的代码是PDO操作数据库类的一个封装,采用了单例模式:

  1. <?php 
  2. /** 
  3.  * MyPDO 
  4.  */ 
  5. class MyPDO 
  6. { 
  7.     protected static $_instance = null; 
  8.     protected $dbName = ''; 
  9.     protected $dsn; 
  10.     protected $dbh; 
  11.       
  12.     /** 
  13.      * 构造 
  14.      *  
  15.      * @return MyPDO 
  16.      */ 
  17.     private function __construct($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) 
  18.     { 
  19.         try { 
  20.             $this->dsn = 'mysql:host='.$dbHost.';dbname='.$dbName; 
  21.             $this->dbh = new PDO($this->dsn, $dbUser, $dbPasswd); 
  22.             $this->dbh->exec('SET character_set_connection='.$dbCharset.', character_set_results='.$dbCharset.', character_set_client=binary'); 
  23.         } <a href="\"/tags.php/catch/\"" target="\"_blank\"">catch</a> (PDOException $e) { 
  24.             $this->outputError($e->getMessage()); 
  25.         } 
  26.     } 
  27.       
  28.     /** 
  29.      * 防止克隆 
  30.      *  
  31.      */ 
  32.     private function __clone() {} 
  33.       
  34.     /** 
  35.      * Singleton instance 
  36.      *  
  37.      * @return Object 
  38.      */ 
  39.     public static function getInstance($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) 
  40.     { 
  41.         if (self::$_instance === null) { 
  42.             self::$_instance = new self($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset); 
  43.         } 
  44.         return self::$_instance; 
  45.     } 
  46.       
  47.     /** 
  48.      * Query 查询 
  49.      * 
  50.      * @param String $strSql SQL语句 
  51.      * @param String $queryMode 查询方式(All or Row) 
  52.      * @param Boolean $debug 
  53.      * @return Array 
  54.      */ 
  55.     public function query($strSql, $queryMode = 'All', $debug = false) 
  56.     { 
  57.         if ($debug === true) $this->debug($strSql); 
  58.         $recordset = $this->dbh->query($strSql); 
  59.         $this->getPDOError(); 
  60.         if ($recordset) { 
  61.             $recordset->setFetchMode(PDO::FETCH_ASSOC); 
  62.             if ($queryMode == 'All') { 
  63.                 $result = $recordset->fetchAll(); 
  64.             } elseif ($queryMode == 'Row') { 
  65.                 $result = $recordset->fetch(); 
  66.             } 
  67.         } else { 
  68.             $result = null; 
  69.         } 
  70.         return $result; 
  71.     } 
  72.       
  73.     /** 
  74.      * Update 更新 
  75.      * 
  76.      * @param String $table 表名 
  77.      * @param Array $arrayDataValue 字段与值 
  78.      * @param String $where 条件 
  79.      * @param Boolean $debug 
  80.      * @return Int 
  81.      */ 
  82.     public function update($table, $arrayDataValue, $where = '', $debug = false) 
  83.     { 
  84.         $this->checkFields($table, $arrayDataValue); 
  85.         if ($where) { 
  86.             $strSql = ''; 
  87.             <a href="\"/tags.php/foreach/\"" target="\"_blank\"">foreach</a> ($arrayDataValue as $key => $value) { 
  88.                 $strSql .= ", `$key`='$value'"; 
  89.             } 
  90.             $strSql = <a href="\"/tags.php/substr/\"" target="\"_blank\"">substr</a>($strSql, 1); 
  91.             $strSql = "UPDATE `$table` SET $strSql WHERE $where"; 
  92.         } else { 
  93.             $strSql = "REPLACE INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; 
  94.         } 
  95.         if ($debug === true) $this->debug($strSql); 
  96.         $result = $this->dbh->exec($strSql); 
  97.         $this->getPDOError(); 
  98.         return $result; 
  99.     } 
  100.       
  101.     /** 
  102.      * Insert 插入 
  103.      * 
  104.      * @param String $table 表名 
  105.      * @param Array $arrayDataValue 字段与值 
  106.      * @param Boolean $debug 
  107.      * @return Int 
  108.      */ 
  109.     public function insert($table, $arrayDataValue, $debug = false) 
  110.     { 
  111.         $this->checkFields($table, $arrayDataValue); 
  112.         $strSql = "INSERT INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; 
  113.         if ($debug === true) $this->debug($strSql); 
  114.         $result = $this->dbh->exec($strSql); 
  115.         $this->getPDOError(); 
  116.         return $result; 
  117.     } 
  118.       
  119.     /** 
  120.      * Replace 覆盖方式插入 
  121.      * 
  122.      * @param String $table 表名 
  123.      * @param Array $arrayDataValue 字段与值 
  124.      * @param Boolean $debug 
  125.      * @return Int 
  126.      */ 
  127.     public function replace($table, $arrayDataValue, $debug = false) 
  128.     { 
  129.         $this->checkFields($table, $arrayDataValue); 
  130.         $strSql = "REPLACE INTO `$table`(`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')"; 
  131.         if ($debug === true) $this->debug($strSql); 
  132.         $result = $this->dbh->exec($strSql); 
  133.         $this->getPDOError(); 
  134.         return $result; 
  135.     } 
  136.       
  137.     /** 
  138.      * Delete 删除 
  139.      * 
  140.      * @param String $table 表名 
  141.      * @param String $where 条件 
  142.      * @param Boolean $debug 
  143.      * @return Int 
  144.      */ 
  145.     public function delete($table, $where = '', $debug = false) 
  146.     { 
  147.         if ($where == '') { 
  148.             $this->outputError("'WHERE' is Null"); 
  149.         } else { 
  150.             $strSql = "DELETE FROM `$table` WHERE $where"; 
  151.             if ($debug === true) $this->debug($strSql); 
  152.             $result = $this->dbh->exec($strSql); 
  153.             $this->getPDOError(); 
  154.             return $result; 
  155.         } 
  156.     } 
  157.       
  158.     /** 
  159.      * execSql 执行SQL语句 
  160.      * 
  161.      * @param String $strSql 
  162.      * @param Boolean $debug 
  163.      * @return Int 
  164.      */ 
  165.     public function execSql($strSql, $debug = false) 
  166.     { 
  167.         if ($debug === true) $this->debug($strSql); 
  168.         $result = $this->dbh->exec($strSql); 
  169.         $this->getPDOError(); 
  170.         return $result; 
  171.     } 
  172.       
  173.     /** 
  174.      * 获取字段最大值 
  175.      *  
  176.      * @param string $table 表名 
  177.      * @param string $field_name 字段名 
  178.      * @param string $where 条件 
  179.      */ 
  180.     public function getMaxValue($table, $field_name, $where = '', $debug = false) 
  181.     { 
  182.         $strSql = "SELECT MAX(".$field_name.") AS MAX_VALUE FROM $table"; 
  183.         if ($where != '') $strSql .= " WHERE $where"; 
  184.         if ($debug === true) $this->debug($strSql); 
  185.         $arrTemp = $this->query($strSql, 'Row'); 
  186.         $maxValue = $arrTemp["MAX_VALUE"]; 
  187.         if ($maxValue == "" || $maxValue == null) { 
  188.             $maxValue = 0; 
  189.         } 
  190.         return $maxValue; 
  191.     } 
  192.       
  193.     /** 
  194.      * 获取指定列的数量 
  195.      *  
  196.      * @param string $table 
  197.      * @param string $field_name 
  198.      * @param string $where 
  199.      * @param bool $debug 
  200.      * @return int 
  201.      */ 
  202.     public function getCount($table, $field_name, $where = '', $debug = false) 
  203.     { 
  204.         $strSql = "SELECT COUNT($field_name) AS NUM FROM $table"; 
  205.         if ($where != '') $strSql .= " WHERE $where"; 
  206.         if ($debug === true) $this->debug($strSql); 
  207.         $arrTemp = $this->query($strSql, 'Row'); 
  208.         return $arrTemp['NUM']; 
  209.     } 
  210.       
  211.     /** 
  212.      * 获取表引擎 
  213.      *  
  214.      * @param String $dbName 库名 
  215.      * @param String $tableName 表名 
  216.      * @param Boolean $debug 
  217.      * @return String 
  218.      */ 
  219.     public function getTableEngine($dbName, $tableName) 
  220.     { 
  221.         $strSql = "SHOW TABLE STATUS FROM $dbName WHERE Name='".$tableName."'"; 
  222.         $arrayTableInfo = $this->query($strSql); 
  223.         $this->getPDOError(); 
  224.         return $arrayTableInfo[0]['Engine']; 
  225.     } 
  226.       
  227.     /** 
  228.      * beginTransaction 事务开始 
  229.      */ 
  230.     private function beginTransaction() 
  231.     { 
  232.         $this->dbh->beginTransaction(); 
  233.     } 
  234.       
  235.     /** 
  236.      * commit 事务提交 
  237.      */ 
  238.     private function commit() 
  239.     { 
  240.         $this->dbh->commit(); 
  241.     } 
  242.       
  243.     /** 
  244.      * rollback 事务回滚 
  245.      */ 
  246.     private function rollback() 
  247.     { 
  248.         $this->dbh->rollback(); 
  249.     } 
  250.       
  251.     /** 
  252.      * transaction 通过事务处理多条SQL语句 
  253.      * 调用前需通过getTableEngine判断表引擎是否支持事务 
  254.      * 
  255.      * @param array $arraySql 
  256.      * @return Boolean 
  257.      */ 
  258.     public function execTransaction($arraySql) 
  259.     { 
  260.         $retval = 1; 
  261.         $this->beginTransaction(); 
  262.         foreach ($arraySql as $strSql) { 
  263.             if ($this->execSql($strSql) == 0) $retval = 0; 
  264.         } 
  265.         if ($retval == 0) { 
  266.             $this->rollback(); 
  267.             return false; 
  268.         } else { 
  269.             $this->commit(); 
  270.             return true; 
  271.         } 
  272.     } 
  273.     /** 
  274.      * checkFields 检查指定字段是否在指定数据表中存在 
  275.      * 
  276.      * @param String $table 
  277.      * @param array $arrayField 
  278.      */ 
  279.     private function checkFields($table, $arrayFields) 
  280.     { 
  281.         $fields = $this->getFields($table); 
  282.         foreach ($arrayFields as $key => $value) { 
  283.             if (!in_array($key, $fields)) { 
  284.                 $this->outputError("Unknown column `$key` in field list."); 
  285.             } 
  286.         } 
  287.     } 
  288.       
  289.     /** 
  290.      * getFields 获取指定数据表中的全部字段名 
  291.      * 
  292.      * @param String $table 表名 
  293.      * @return array 
  294.      */ 
  295.     private function getFields($table) 
  296.     { 
  297.         $fields = array(); 
  298.         $recordset = $this->dbh->query("SHOW COLUMNS FROM $table"); 
  299.         $this->getPDOError(); 
  300.         $recordset->setFetchMode(PDO::FETCH_ASSOC); 
  301.         $result = $recordset->fetchAll(); 
  302.         foreach ($result as $rows) { 
  303.             $fields[] = $rows['Field']; 
  304.         } 
  305.         return $fields; 
  306.     } 
  307.       
  308.     /** 
  309.      * getPDOError 捕获PDO错误信息 
  310.      */ 
  311.     private function getPDOError() 
  312.     { 
  313.         if ($this->dbh->errorCode() != '00000') { 
  314.             $arrayError = $this->dbh->errorInfo(); 
  315.             $this->outputError($arrayError[2]); 
  316.         } 
  317.     } 
  318.       
  319.     /** 
  320.      * debug 
  321.      *  
  322.      * @param mixed $debuginfo 
  323.      */ 
  324.     private function debug($debuginfo) 
  325.     { 
  326.         var_dump($debuginfo); 
  327.         exit(); 
  328.     } 
  329.       
  330.     /** 
  331.      * 输出错误信息 
  332.      *  
  333.      * @param String $strErrMsg 
  334.      */ 
  335.     private function outputError($strErrMsg) 
  336.     { 
  337.         throw new Exception('MySQL Error: '.$strErrMsg); 
  338.     } 
  339.       
  340.     /** 
  341.      * destruct 关闭数据库连接 
  342.      */ 
  343.     public function destruct() 
  344.     { 
  345.         $this->dbh = null; 
  346.     } 
  347. } 
  348. ?> 

调用方法:

  1. <?php 
  2. require 'MyPDO.class.php'; 
  3. $db = MyPDO::getInstance('localhost', 'root', '123456', 'test', 'utf8'); 
  4. $db->query("<a href="\"/tags.php/select/\"" target="\"_blank\"">select</a> count(*) frome table"); 
  5. $db->destruct(); 
  6. ?> 

Tags: PHP单例模式 PHP优点意义

分享到: