首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 多例模式深度解析:鍵值管理多實例、記憶體優化與衝突避免

     編輯:PHP 綜合知識

多例模式核心定義

相對於單例模式「全域唯一實例」,多例模式允許同一類擁有多個實例,但針對給定的鍵值組合只存在唯一實例。核心特徵:

  1. 多例類可擁有多個實例
  2. 自我創建並管理實例,透過 getInstance() 提供存取
  3. 相同參數(鍵值)返回同一實例,不同參數返回不同實例

經典實作代碼 (來源:Wikipedia)

<?php
abstract class Multiton {
  private static $instances = array();

  public static function getInstance() {
    // 以「類名 + 序列化參數」作為唯一鍵
    $key = get_called_class() . serialize(func_get_args());
    
    if (!isset(self::$instances[$key])) {
      $rc = new ReflectionClass(get_called_class());
      self::$instances[$key] = $rc->newInstanceArgs(func_get_args());
    }
    return self::$instances[$key];
  }
}

// 子類繼承 Multiton
class Hello extends Multiton {
  public function __construct($string = 'World') {
    echo "Hello $string\n";
  }
}

class GoodBye extends Multiton {
  public function __construct($string = 'my', $string2 = 'darling') {
    echo "Goodbye $string $string2\n";
  }
}

// 測試驗證
$a = Hello::getInstance('World');
$b = Hello::getInstance('bob');      // 參數不同 → 新實例
// $a !== $b

$c = Hello::getInstance('World');    // 參數相同 → 同一實例
// $a === $c

$d = GoodBye::getInstance();
$e = GoodBye::getInstance();         // 無參數 → 同一實例
// $d === $e

$f = GoodBye::getInstance('your');   // 參數不同 → 新實例
// $d !== $f
?>

關鍵技術點解析

1. 鍵值生成策略

$key = get_called_class() . serialize(func_get_args());
  • get_called_class():晚期靜態綁定,獲取實際調用的子類名
  • func_get_args():獲取所有傳入參數陣列
  • serialize():將參數序列化為字串,確保複雜參數也能作為鍵

2. 實例創建機制

$rc = new ReflectionClass(get_called_class());
self::$instances[$key] = $rc->newInstanceArgs(func_get_args());
  • 使用 ReflectionClass 動態實例化,支援任意建構子參數
  • newInstanceArgs() 接受參數陣列,完美轉發建構子參數

3. 靜態儲存容器

private static $instances 以陣列儲存所有實例,鍵為上述生成的唯一標識,值為物件實例。

優勢與應用場景

優勢說明
記憶體優化相同參數複用實例,避免重複創建
衝突避免不同參數隔離實例,狀態不互相干擾
資源池化適用於資料庫連線池、快取物件、配置管理器等
參數化單例可視為「帶參數的單例」,擴展性極強

實際應用範例:資料庫連線池

class DBConnection extends Multiton {
  private $pdo;
  
  public function __construct($host, $dbname, $user, $pass) {
    $dsn = "mysql:host=$host;dbname=$dbname;charset=utf8";
    $this->pdo = new PDO($dsn, $user, $pass, [
      PDO::ATTR_PERSISTENT => true
    ]);
  }
  
  public function getPDO() { return $this->pdo; }
}

// 不同資料庫配置自動獲取不同連線實例
$mainDB = DBConnection::getInstance('localhost', 'main_db', 'user', 'pass');
$logDB  = DBConnection::getInstance('localhost', 'log_db', 'user', 'pass');
$mainDB2 = DBConnection::getInstance('localhost', 'main_db', 'user', 'pass');
// $mainDB === $mainDB2 (同配置複用)
// $mainDB !== $logDB (不同資料庫隔離)

注意事項

  • PHP 5.3+ 才支援 get_called_class() 晚期靜態綁定
  • 建構子建議設為 protected 防止外部直接 new
  • 序列化參數需確保可序列化(資源型別會失效)
  • 長期運行需考慮實例清理機制防止記憶體洩漏
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved