PHP与设计模式:单例模式详解与实战

2022-03-02T12:00:00

PHP 单例模式详解与实战

单例模式(Singleton Pattern)是软件设计中的一种常用模式,它确保一个类在整个应用中只有一个实例,同时提供全局访问点。单例模式广泛应用于日志记录、数据库连接、配置管理等场景。


1. 单例模式简介

  • 定义:单例模式是一种创建型设计模式,它确保某个类只有一个实例,并且提供一个访问该实例的全局方法。
  • 特点:
    唯一性:单例类只能有一个实例。
    全局访问点:提供一个静态方法,用于获取实例。
    延迟加载:在首次访问时才创建实例。

2. 单例模式的实现步骤

  1. 私有化构造函数:防止外部通过 new 创建实例。
  2. 私有化克隆方法:禁止对象被克隆。
  3. 创建静态属性存储实例:用于保存类的唯一实例。
  4. 提供静态方法获取实例:确保实例的唯一性。

3. PHP 单例模式实现

以下是单例模式的完整代码示例:

<?php

class Singleton {
    // 静态属性,存放唯一实例
    private static $instance = null;

    // 私有化构造函数,禁止外部实例化
    private function __construct() {
        echo "Instance created." . PHP_EOL;
    }

    // 禁止克隆对象
    private function __clone() {}

    // 禁止反序列化
    private function __wakeup() {}

    // 静态方法,提供全局访问点
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

// 测试单例模式
$instance1 = Singleton::getInstance(); // 输出: Instance created.
$instance2 = Singleton::getInstance();

var_dump($instance1 === $instance2); // 输出: bool(true)
?>

4.代码解析

private static $instance

用于存储单例对象。初始值为 null。
private function __construct()

将构造函数私有化,阻止外部直接创建对象。
public static function getInstance()

静态方法,负责检查并创建实例。如果实例不存在(null),则创建实例;否则返回已有实例。
private function __clone() 和 private function __wakeup()

分别禁止克隆和反序列化,确保实例唯一性。


5. 单例模式的应用场景

  1. 数据库连接
    数据库连接通常只需要一个实例,使用单例模式可以避免重复创建连接。

    <?php
    
    class Database {
     private static $instance = null;
     private $connection;
    
     private function __construct() {
         // 创建数据库连接
         $this->connection = new PDO('mysql:host=localhost;dbname=test', 'root', '');
     }
    
     public static function getInstance() {
         if (self::$instance === null) {
             self::$instance = new self();
         }
         return self::$instance;
     }
    
     public function getConnection() {
         return $this->connection;
     }
    }
    
    // 测试
    $db1 = Database::getInstance()->getConnection();
    $db2 = Database::getInstance()->getConnection();
    
    var_dump($db1 === $db2); // 输出: bool(true)
    ?>
  2. 配置管理
    在项目中,配置通常是全局共享的,使用单例模式可以确保配置管理的一致性。

    <?php
    
    class Config {
     private static $instance = null;
     private $settings = [];
    
     private function __construct() {}
    
     public static function getInstance() {
         if (self::$instance === null) {
             self::$instance = new self();
         }
         return self::$instance;
     }
    
     public function set($key, $value) {
         $this->settings[$key] = $value;
     }
    
     public function get($key) {
         return $this->settings[$key] ?? null;
     }
    }
    
    // 测试
    $config = Config::getInstance();
    $config->set('app_name', 'My Application');
    echo $config->get('app_name'); // 输出: My Application
    ?>
  3. 日志记录
    日志记录器需要全局访问,但避免多次实例化。

    <?php
    
    class Logger {
     private static $instance = null;
    
     private function __construct() {}
    
     public static function getInstance() {
         if (self::$instance === null) {
             self::$instance = new self();
         }
         return self::$instance;
     }
    
     public function log($message) {
         echo "[LOG]: $message" . PHP_EOL;
     }
    }
    
    // 测试
    Logger::getInstance()->log('This is a log message.');
    Logger::getInstance()->log('This is another log message.');
    ?>

6. 单例模式的优缺点

  • 优点:
    节省资源:避免重复创建对象,节省内存。
    全局访问点:简化对象管理,提高代码可维护性。
    实现简单:代码实现容易理解和扩展。
  • 缺点:
    多线程问题:在多线程环境中,需要注意线程安全(如PHP的WebSocket或CLI多线程)。
    隐藏依赖:由于实例是静态获取,可能导致代码难以测试和维护。
    全局状态:可能引入难以追踪的全局状态。

7. 多线程环境中的单例

在多线程环境下,单例模式需要通过加锁机制确保线程安全:

<?php

class ThreadSafeSingleton {
    private static $instance = null;
    private static $lock = false;

    private function __construct() {}

    public static function getInstance() {
        if (self::$instance === null) {
            // 加锁,确保线程安全
            if (!self::$lock) {
                self::$lock = true;
                self::$instance = new self();
                self::$lock = false;
            }
        }
        return self::$instance;
    }
}
?>
当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »