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

PHP 設計模式:單例模式 完整實作與核心原理深度解析

     編輯:PHP 綜合知識

單例模式是最基礎也最常用的建構型設計模式,確保類別在全域只有唯一實例,並提供全域存取點。本文以資料庫連線類別為例,完整展示 PHP 單例實作細節,並逐步拆解「為什麼這樣寫」的核心邏輯。

標準單例實作程式碼

<?php
class EasyFramework_Easy_Mysql {
    // 靜態私有屬性:保存唯一實例
    protected static $_instance = null;

    // 私有建構子:禁止外部 new
    private function __construct() {
        // 實際連線邏輯:new PDO(...)
    }

    // 禁止克隆
    protected function __clone() {}

    // 禁止反序列化(PHP 7.1+)
    public function __wakeup() {
        throw new \Exception('Cannot unserialize singleton');
    }

    // 公開靜態方法:取得唯一實例
    public static function getInstance() {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
}

// 使用方式
$db = EasyFramework_Easy_Mysql::getInstance();
var_dump($db);
?>

七大核心步驟深度解析

  1. 私有建構子:private function __construct() 讓外部無法 new Class(),掌握實例化控制權。
  2. 靜態私有屬性:protected static $_instance = null 以類別層級儲存唯一實例,不屬於任何物件。
  3. 公開靜態存取器:public static function getInstance() 提供全域唯一存取點,呼叫方式 Class::getInstance()。
  4. 延遲初始化:首次呼叫時 $_instance === null 為真,建立實例並賦值;後續呼叫直接回傳既有實例。
  5. 防止克隆:__clone() 設為 protected/private,避免 clone $instance 產生副本。
  6. 防止反序列化:實作 __wakeup() 拋出例外,防止 unserialize() 繞過建構子重建實例。
  7. 執行緒安全(PHP-FPM 無需額外處理):PHP 是共享無記憶體架構,每個請求獨立進程,單例天然隔離,無競態問題。

實際應用場景

  • 資料庫連線:避免重複建立連線、耗盡連線池。
  • 配置管理:全域唯一配置物件,避免重複解析檔案。
  • 日誌記錄器:單一寫入通道,確保日誌順序、檔案鎖正確。
  • 快取管理器:統一快取實例,避免多實例造成資料不一致。

常見誤區與反模式

誤區說明正確做法
濫用單例當全域變數任何需要共享狀態的地方都用單例,導致耦合度極高、難以測試依賴注入(DI 容器)管理共享服務,單例僅用於真正需要「全程唯一」的資源
單例類別過於龐大把所有功能塞進單例,違反單一職責拆分為多個單一職責服務,由 DI 容器管理生命週期
忽略 __clone / __wakeup可被克隆或反序列化產生多實例務必宣告並拋出例外
建構子執行重度邏輯連線失敗拋出例外導致單例永遠無法取得建構子僅初始化屬性,連線放在 connect() 方法延遲執行

現代 PHP 框架中的單例

Laravel、Symfony 等框架透過 服務容器 綁定 singleton,實際上是「容器管理的單例」而非類別自行實作:

<?php
// Laravel 服務提供者中
$this->app->singleton('db', function ($app) {
    return new DatabaseConnection($app['config']['database']);
});

// 任何地方解析
$db = app('db'); // 永遠回傳同一實例
?>

這樣既保有單例優勢,又維持可測試性(測試時可綁定 mock 物件)。

總結

單例模式核心在於「私有建構子 + 靜態實例屬性 + 靜態存取器」。理解其七大步驟邏輯,能幫你在適當場合正確應用,避免濫用導致的架構腐化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved