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

调用方法:

  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优点意义

分享到: