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

PHP 單例模式深度解析:原理、實現與最佳實踐

     編輯:PHP 綜合知識

什麼是單例模式?

確保一個類在全局範圍內**僅有一個實例**,並提供一個全局訪問點。核心職責:控制實例化過程,防止多次 new 消耗資源或狀態不一致。

單例模式三大核心要素

  1. 私有構造函數:private function __construct() 防止外部 new。
  2. 私有靜態實例屬性:private static $_instance = null; 保存唯一實例。
  3. 公有靜態獲取方法:public static function getInstance() 延遲實例化並返回引用。

輔助:防止克隆:private function __clone() 拋出錯誤。

標準實現代碼(PHP 7+ 嚴格類型)

<?php
declare(strict_types=1);

class Database {
    private static ?self $_instance = null;
    private \PDO $pdo;

    // 1. 私有構造:完成資源初始化
    private function __construct() {
        $dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4';
        $this->pdo = new \PDO($dsn, 'user', 'pass', [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
        ]);
        echo "Database connected.\n";
    }

    // 2. 防止克隆
    private function __clone() {
        throw new \LogicException('Cloning singleton is forbidden.');
    }

    // 3. 防止反序列化(可選)
    public function __wakeup() {
        throw new \LogicException('Unserializing singleton is forbidden.');
    }

    // 4. 獲取唯一實例
    public static function getInstance(): self {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    // 業務方法
    public function query(string $sql, array $params = []): array {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }
}

// 使用方式
$db = Database::getInstance();
$users = $db->query('SELECT * FROM users WHERE status = ?', [1]);

// 嘗試克隆將拋出異常
// $db2 = clone $db; // LogicException

為什麼在 PHP 中使用單例?

場景收益
資料庫連接避免重複建立 TCP 連接、認證握手,節省資源與延遲
配置管理全局唯一配置中心,運行時熱更新、多模組共享
日誌記錄器單一寫入通道,避免文件句柄衝突、格式統一
快取客戶端Redis/Memcached 連接池復用

常見誤區與反模式

  1. 濫用單例:將所有服務都做成單例導致強耦合、難以單元測試。
    → 建議:僅對「資源型、狀態型、昂貴初始化」對象使用;業務邏輯類優先用依賴注入(DI 容器)。
  2. 忽略執行緒安全:PHP-FPM 多進程模型下,單例僅在**單個請求生命週期**內唯一,跨請求不共享。若需跨進程共享,需用 Redis/共享內存等外部存儲。
  3. 靜態屬性污染測試:單例狀態殘留影響後續測試用例。
    → 解決:提供 resetInstance() 僅供測試環境調用,或使用 runkit/uopz 重置。

現代 PHP 框架中的單例

  • Laravel:服務容器綁定 singleton,實例由容器管理生命週期,支援自動注入、介面綁定、標籤解析。
  • Symfony:服務預設即為單例,通過 services.yaml 配置 shared: true(預設)。
  • Hyperf/Swoole:長連接場景下,單例實例駐留內存跨請求復用,需注意狀態隔離(請求級數據勿存單例)。

總結

單例模式是「雙刃劍」:正確使用能優化資源佔用、簡化全局訪問;濫用則導致隱式依賴、測試困難、擴展受限。**原則:資源型單例,業務型依賴注入。**

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