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

PHP 單例模式最佳實踐:資料庫連接、配置管理、日誌服務的標準實現

     編輯:PHP 相關知識

單例模式確保類全局僅有一實例,並提供訪問點。PHP 中主要用於資料庫連接、配置管理、日誌服務等資源密集型對象。本文給出生產級標準實現,含防克隆、防序列化、延遲初始化、線程安全 (Swoole 環境) 等完善細節。

核心三要素

  1. 私有構造函數:阻止 new Class()。
  2. 私有靜態實例屬性:保存唯一實例。
  3. 公共靜態獲取方法:getInstance() 延遲初始化並返回實例。

標準實現 (PHP 7.4+)

final class Database {
    private static ?self $instance = null;
    private PDO $pdo;

    // 防止外部實例化
    private function __construct() {
        $this->pdo = new PDO(
            "mysql:host=localhost;dbname=test;charset=utf8mb4",
            'user', 'pass',
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
    }

    // 防止克隆
    private function __clone() {}

    // 防止反序列化
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }

    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    // 代理 PDO 方法
    public function __call(string $method, array $args) {
        return $this->pdo->$method(...$args);
    }
}

// 使用
$db = Database::getInstance();
$stmt = $db->query("SELECT * FROM users");

Swoole/多進程環境下的線程安全單例

Swoole Worker 進程間內存隔離,單例需配合進程 ID 或共享內存:

class Singleton {
    private static array $instances = [];

    public static function getInstance(): self {
        $pid = getmypid(); // 或 Swoole\Process::getPid()
        if (!isset(self::$instances[$pid])) {
            self::$instances[$pid] = new self();
        }
        return self::$instances[$pid];
    }
}

依賴注入容器中的單例綁定 (Laravel 示例)

// AppServiceProvider::register()
$this->app->singleton(Database::class, function ($app) {
    return new Database(
        $app['config']['database.connections.mysql']
    );
});

// 控制器自動注入
public function index(Database $db) { ... }

容器管理生命周期,比手寫單例更靈活、可測試。

反模式警示

  • 濫用單例作為全局變量容器:導致隱式依賴、難以單元測試、並發狀態污染。
  • 單例內持有請求級狀態:如用戶身份、輸入數據,必須按請求作用域綁定。
  • 忽略 __wakeup/__clone:序列化/克隆可破壞單例性。

何時使用單例

| 適用場景 | 不適用場景 | |------------|------------| | 資源連接池 (DB/Redis/ES) | 業務邏輯服務類 | | 配置管理器 | 請求上下文對象 | | 日誌/監控客戶端 | 有狀態的領域服務 | | 硬體設備驅動 | 任何可多實例協作的組件 |

單例是「全局唯一訪問點」而非「全局變量」,克制使用、封裝內部狀態、配合容器管理,才是成熟架構的表現。

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