溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

php如何實(shí)現(xiàn)單例模式

發(fā)布時(shí)間:2021-06-25 12:28:48 來源:億速云 閱讀:156 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“php如何實(shí)現(xiàn)單例模式”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“php如何實(shí)現(xiàn)單例模式”這篇文章吧。

一、什么是單例模式?
1、含義   
   作為對象的創(chuàng)建模式,單例模式確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)全局地提供這個(gè)實(shí)例。它不會(huì)創(chuàng)建實(shí)例副本,而是會(huì)向單例類內(nèi)部存儲的實(shí)例返回一個(gè)引用。
2、單例模式的三個(gè)要點(diǎn):
(1). 需要一個(gè)保存類的唯一實(shí)例的靜態(tài)成員變量:
private static $_instance;   
(2). 構(gòu)造函數(shù)和克隆函數(shù)必須聲明為私有的,防止外部程序new類從而失去單例模式的意義:

private function __construct()  
{  
  $this->_db = pg_connect('xxxx'); 
}  
private function __clone() 
{ 
}//覆蓋__clone()方法,禁止克隆

(3). 必須提供一個(gè)訪問這個(gè)實(shí)例的公共的靜態(tài)方法(通常為getInstance方法),從而返回唯一實(shí)例的一個(gè)引用

public static function getInstance()  
{  
  if(! (self::$_instance instanceof self) )  
  {  
    self::$_instance = new self();  
  } 
  return self::$_instance;  
 
}

二、為什么要使用單例模式?
1、PHP缺點(diǎn):
        
        PHP語言是一種解釋型的腳本語言,這種運(yùn)行機(jī)制使得每個(gè)PHP頁面被解釋執(zhí)行后,所有的相關(guān)資源都會(huì)被回收。也就是說,PHP在語言級別上沒有辦法讓某個(gè)對象常駐內(nèi)存,這和asp.net、Java等編譯型是不同的,比如在Java中單例會(huì)一直存在于整個(gè)應(yīng)用程序的生命周期里,變量是跨頁面級的,真正可以做到這個(gè)實(shí)例在應(yīng)用程序生命周期中的唯一性。然而在PHP中,所有的變量無論是全局變量還是類的靜態(tài)成員,都是頁面級的,每次頁面被執(zhí)行時(shí),都會(huì)重新建立新的對象,都會(huì)在頁面執(zhí)行完畢后被清空,這樣似乎PHP單例模式就沒有什么意義了,所以PHP單例模式我覺得只是針對單次頁面級請求時(shí)出現(xiàn)多個(gè)應(yīng)用場景并需要共享同一對象資源時(shí)是非常有意義的。

2、單例模式在PHP中的應(yīng)用場合:
(1)、應(yīng)用程序與數(shù)據(jù)庫交互
  一個(gè)應(yīng)用中會(huì)存在大量的數(shù)據(jù)庫操作,比如過數(shù)據(jù)庫句柄來連接數(shù)據(jù)庫這一行為,使用單例模式可以避免大量的new操作,因?yàn)槊恳淮蝞ew操作都會(huì)消耗內(nèi)存資源和系統(tǒng)資源。
(2)、控制配置信息
 如果系統(tǒng)中需要有一個(gè)類來全局控制某些配置信息, 那么使用單例模式可以很方便的實(shí)現(xiàn).

三、如何實(shí)現(xiàn)單例模式?
1、普通的數(shù)據(jù)庫訪問例子:

<?php 
...... 
//初始化一個(gè)數(shù)據(jù)庫句柄 
$db = new DB(...); 
 
//添加用戶信息 
$db->addUserInfo(...); 
 
...... 
 
//在函數(shù)中訪問數(shù)據(jù)庫,查找用戶信息 
function getUserInfo() 
{ 
  $db = new DB(...);//再次new 數(shù)據(jù)庫類,和數(shù)據(jù)庫建立連接 
  $db = query(....);//根據(jù)查詢語句訪問數(shù)據(jù)庫 
} 
 
?>

2、應(yīng)用單例模式對數(shù)據(jù)庫進(jìn)行操作:

<?php 
class DB  
{  
  private $_db;  
  private static $_instance;  
  
  private function __construct(...)  
  {  
    $this->_db = pg_connect(...);//postgrsql  
  }  
  
  private function __clone() {}; //覆蓋__clone()方法,禁止克隆  
  
  public static function getInstance()  
  {  
    if(! (self::$_instance instanceof self) ) {  
      self::$_instance = new self();  
    }  
    return self::$_instance;  
  }  
  
  public function addUserInfo(...) 
  { 
  } 
   public function getUserInfo(...) 
  {  
  } 
 
} 
 
//test  
$db = DB::getInstance();  
$db->addUserInfo(...);  
$db->getUserInfo(...);  
 
?>

 下面的代碼是PDO操作數(shù)據(jù)庫類的一個(gè)封裝,采用了單例模式:

<?php
/**
 * MyPDO
 */
class MyPDO
{
  protected static $_instance = null;
  protected $dbName = '';
  protected $dsn;
  protected $dbh;
  
  /**
   * 構(gòu)造
   * 
   * @return MyPDO
   */
  private function __construct($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset)
  {
    try {
      $this->dsn = 'mysql:host='.$dbHost.';dbname='.$dbName;
      $this->dbh = new PDO($this->dsn, $dbUser, $dbPasswd);
      $this->dbh->exec('SET character_set_connection='.$dbCharset.', character_set_results='.$dbCharset.', character_set_client=binary');
    } catch (PDOException $e) {
      $this->outputError($e->getMessage());
    }
  }
  
  /**
   * 防止克隆
   * 
   */
  private function __clone() {}
  
  /**
   * Singleton instance
   * 
   * @return Object
   */
  public static function getInstance($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset)
  {
    if (self::$_instance === null) {
      self::$_instance = new self($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset);
    }
    return self::$_instance;
  }
  
  /**
   * Query 查詢
   *
   * @param String $strSql SQL語句
   * @param String $queryMode 查詢方式(All or Row)
   * @param Boolean $debug
   * @return Array
   */
  public function query($strSql, $queryMode = 'All', $debug = false)
  {
    if ($debug === true) $this->debug($strSql);
    $recordset = $this->dbh->query($strSql);
    $this->getPDOError();
    if ($recordset) {
      $recordset->setFetchMode(PDO::FETCH_ASSOC);
      if ($queryMode == 'All') {
        $result = $recordset->fetchAll();
      } elseif ($queryMode == 'Row') {
        $result = $recordset->fetch();
      }
    } else {
      $result = null;
    }
    return $result;
  }
  
  /**
   * Update 更新
   *
   * @param String $table 表名
   * @param Array $arrayDataValue 字段與值
   * @param String $where 條件
   * @param Boolean $debug
   * @return Int
   */
  public function update($table, $arrayDataValue, $where = '', $debug = false)
  {
    $this->checkFields($table, $arrayDataValue);
    if ($where) {
      $strSql = '';
      foreach ($arrayDataValue as $key => $value) {
        $strSql .= ", `$key`='$value'";
      }
      $strSql = substr($strSql, 1);
      $strSql = "UPDATE `$table` SET $strSql WHERE $where";
    } else {
      $strSql = "REPLACE INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')";
    }
    if ($debug === true) $this->debug($strSql);
    $result = $this->dbh->exec($strSql);
    $this->getPDOError();
    return $result;
  }
  
  /**
   * Insert 插入
   *
   * @param String $table 表名
   * @param Array $arrayDataValue 字段與值
   * @param Boolean $debug
   * @return Int
   */
  public function insert($table, $arrayDataValue, $debug = false)
  {
    $this->checkFields($table, $arrayDataValue);
    $strSql = "INSERT INTO `$table` (`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')";
    if ($debug === true) $this->debug($strSql);
    $result = $this->dbh->exec($strSql);
    $this->getPDOError();
    return $result;
  }
  
  /**
   * Replace 覆蓋方式插入
   *
   * @param String $table 表名
   * @param Array $arrayDataValue 字段與值
   * @param Boolean $debug
   * @return Int
   */
  public function replace($table, $arrayDataValue, $debug = false)
  {
    $this->checkFields($table, $arrayDataValue);
    $strSql = "REPLACE INTO `$table`(`".implode('`,`', array_keys($arrayDataValue))."`) VALUES ('".implode("','", $arrayDataValue)."')";
    if ($debug === true) $this->debug($strSql);
    $result = $this->dbh->exec($strSql);
    $this->getPDOError();
    return $result;
  }
  
  /**
   * Delete 刪除
   *
   * @param String $table 表名
   * @param String $where 條件
   * @param Boolean $debug
   * @return Int
   */
  public function delete($table, $where = '', $debug = false)
  {
    if ($where == '') {
      $this->outputError("'WHERE' is Null");
    } else {
      $strSql = "DELETE FROM `$table` WHERE $where";
      if ($debug === true) $this->debug($strSql);
      $result = $this->dbh->exec($strSql);
      $this->getPDOError();
      return $result;
    }
  }
  
  /**
   * execSql 執(zhí)行SQL語句
   *
   * @param String $strSql
   * @param Boolean $debug
   * @return Int
   */
  public function execSql($strSql, $debug = false)
  {
    if ($debug === true) $this->debug($strSql);
    $result = $this->dbh->exec($strSql);
    $this->getPDOError();
    return $result;
  }
  
  /**
   * 獲取字段最大值
   * 
   * @param string $table 表名
   * @param string $field_name 字段名
   * @param string $where 條件
   */
  public function getMaxValue($table, $field_name, $where = '', $debug = false)
  {
    $strSql = "SELECT MAX(".$field_name.") AS MAX_VALUE FROM $table";
    if ($where != '') $strSql .= " WHERE $where";
    if ($debug === true) $this->debug($strSql);
    $arrTemp = $this->query($strSql, 'Row');
    $maxValue = $arrTemp["MAX_VALUE"];
    if ($maxValue == "" || $maxValue == null) {
      $maxValue = 0;
    }
    return $maxValue;
  }
  
  /**
   * 獲取指定列的數(shù)量
   * 
   * @param string $table
   * @param string $field_name
   * @param string $where
   * @param bool $debug
   * @return int
   */
  public function getCount($table, $field_name, $where = '', $debug = false)
  {
    $strSql = "SELECT COUNT($field_name) AS NUM FROM $table";
    if ($where != '') $strSql .= " WHERE $where";
    if ($debug === true) $this->debug($strSql);
    $arrTemp = $this->query($strSql, 'Row');
    return $arrTemp['NUM'];
  }
  
  /**
   * 獲取表引擎
   * 
   * @param String $dbName 庫名
   * @param String $tableName 表名
   * @param Boolean $debug
   * @return String
   */
  public function getTableEngine($dbName, $tableName)
  {
    $strSql = "SHOW TABLE STATUS FROM $dbName WHERE Name='".$tableName."'";
    $arrayTableInfo = $this->query($strSql);
    $this->getPDOError();
    return $arrayTableInfo[0]['Engine'];
  }
  
  /**
   * beginTransaction 事務(wù)開始
   */
  private function beginTransaction()
  {
    $this->dbh->beginTransaction();
  }
  
  /**
   * commit 事務(wù)提交
   */
  private function commit()
  {
    $this->dbh->commit();
  }
  
  /**
   * rollback 事務(wù)回滾
   */
  private function rollback()
  {
    $this->dbh->rollback();
  }
  
  /**
   * transaction 通過事務(wù)處理多條SQL語句
   * 調(diào)用前需通過getTableEngine判斷表引擎是否支持事務(wù)
   *
   * @param array $arraySql
   * @return Boolean
   */
  public function execTransaction($arraySql)
  {
    $retval = 1;
    $this->beginTransaction();
    foreach ($arraySql as $strSql) {
      if ($this->execSql($strSql) == 0) $retval = 0;
    }
    if ($retval == 0) {
      $this->rollback();
      return false;
    } else {
      $this->commit();
      return true;
    }
  }
  /**
   * checkFields 檢查指定字段是否在指定數(shù)據(jù)表中存在
   *
   * @param String $table
   * @param array $arrayField
   */
  private function checkFields($table, $arrayFields)
  {
    $fields = $this->getFields($table);
    foreach ($arrayFields as $key => $value) {
      if (!in_array($key, $fields)) {
        $this->outputError("Unknown column `$key` in field list.");
      }
    }
  }
  
  /**
   * getFields 獲取指定數(shù)據(jù)表中的全部字段名
   *
   * @param String $table 表名
   * @return array
   */
  private function getFields($table)
  {
    $fields = array();
    $recordset = $this->dbh->query("SHOW COLUMNS FROM $table");
    $this->getPDOError();
    $recordset->setFetchMode(PDO::FETCH_ASSOC);
    $result = $recordset->fetchAll();
    foreach ($result as $rows) {
      $fields[] = $rows['Field'];
    }
    return $fields;
  }
  
  /**
   * getPDOError 捕獲PDO錯(cuò)誤信息
   */
  private function getPDOError()
  {
    if ($this->dbh->errorCode() != '00000') {
      $arrayError = $this->dbh->errorInfo();
      $this->outputError($arrayError[2]);
    }
  }
  
  /**
   * debug
   * 
   * @param mixed $debuginfo
   */
  private function debug($debuginfo)
  {
    var_dump($debuginfo);
    exit();
  }
  
  /**
   * 輸出錯(cuò)誤信息
   * 
   * @param String $strErrMsg
   */
  private function outputError($strErrMsg)
  {
    throw new Exception('MySQL Error: '.$strErrMsg);
  }
  
  /**
   * destruct 關(guān)閉數(shù)據(jù)庫連接
   */
  public function destruct()
  {
    $this->dbh = null;
  }
}
?>

調(diào)用方法:

<?php
require 'MyPDO.class.php';
$db = MyPDO::getInstance('localhost', 'root', '123456', 'test', 'utf8');
$db->query("select count(*) frome table");
$db->destruct();
?>

以上是“php如何實(shí)現(xiàn)單例模式”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI