php设计模式之单例模式详解

单例模式(Singleton Pattern)是 PHP 设计模式中最常用的模式之一,它确保一个类只有一个实例,并提供全局访问点。这种模式特别适合需要全局唯一对象的场景,如数据库连接、日志记录器等。


一、单例模式核心思想

  1. 禁止外部实例化:通过私有化构造函数实现

  2. 禁止克隆对象:通过私有化 __clone() 方法实现

  3. 禁止反序列化:通过私有化 __wakeup() 方法实现(PHP 7.4+)

  4. 静态方法获取实例:通过静态方法统一提供实例


二、PHP 单例模式标准实现

class Singleton
{
    // 1. 静态变量保存唯一实例
    private static $instance = null;

    // 2. 私有构造函数防止外部实例化
    private function __construct()
    {
        // 初始化代码
    }

    // 3. 禁止克隆
    private function __clone() {}

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

    // 5. 全局访问点
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    // 示例方法
    public function showMessage()
    {
        echo "I am a singleton instance!";
    }
}

三、使用示例

// 获取实例
$instance1 = Singleton::getInstance();
$instance2 = Singleton::getInstance();

// 验证唯一性
var_dump($instance1 === $instance2); // 输出 bool(true)

// 调用方法
$instance1->showMessage(); // 输出 "I am a singleton instance!"

// 尝试非法操作
// new Singleton(); // 致命错误
// clone $instance1; // 致命错误
// unserialize(serialize($instance1)); // 抛出异常

四、关键特性解析

特性 实现方式 作用
单一实例 静态变量 $instance 保证全局唯一对象
防止实例化 私有构造函数 __construct 禁止通过 new 创建实例
防止克隆 私有 __clone() 方法 禁止通过 clone 复制实例
防止反序列化 自定义 __wakeup() 防止通过反序列化创建新实例
延迟初始化 getInstance() 中的判断 需要时才创建实例,节省资源

五、适用场景

  1. 数据库连接:避免频繁创建连接消耗资源

  2. 日志记录器:统一管理日志写入

  3. 配置管理:全局共享配置信息

  4. 缓存系统:统一管理缓存资源

  5. 线程池/连接池:管理有限资源


六、高级技巧

1. 继承单例基类(PHP 7+)
abstract class BaseSingleton
{
    private static $instances = [];

    protected function __construct() {}

    public static function getInstance()
    {
        $class = static::class;
        if (!isset(self::$instances[$class])) {
            self::$instances[$class] = new static();
        }
        return self::$instances[$class];
    }

    // 其他单例方法同上...
}

class Database extends BaseSingleton {}
class Logger extends BaseSingleton {}
2. 线程安全版(需安装 pthreads 扩展)
class ThreadSafeSingleton
{
    private static $instance = null;
    private static $lock = null;

    private function __construct()
    {
        self::$lock = \Mutex::create();
    }

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

七、注意事项

  1. 单元测试困难:全局状态会影响测试结果

  2. 隐藏依赖关系:降低代码可维护性

  3. 违反单一职责原则:同时管理实例创建和业务逻辑

  4. 生命周期管理:无法主动销毁实例

  5. 多线程环境:PHP 默认不支持真正线程,需特殊处理


八、性能优化建议

  1. 急切初始化:在 getInstance() 之前直接创建实例

  2. 双重检查锁:适用于多线程环境(需配合扩展)

  3. 使用依赖注入:替代全局访问,提高可测试性

  4. PSR-11 容器:使用容器管理单例更规范


九、替代方案

  1. 依赖注入:通过容器管理对象生命周期

  2. 静态类:适用于无状态工具类

  3. 服务定位器:更灵活的全局访问方式

  4. Monostate 模式:通过静态变量共享状态


单例模式是把双刃剑,在 PHP 中应谨慎使用。对于现代 PHP 开发,推荐优先考虑依赖注入容器(如 Laravel 的 Service Container)来管理对象生命周期,既能保持单例的优势,又能避免传统单例模式的缺陷。

你可能感兴趣的:(php,php,设计模式,单例模式)