概述
单例模式是 PHP 中最常用的创建型设计模式之一,核心目标是保证一个类在整个应用生命周期内仅有一个实例,并提供全局统一的访问入口。其核心价值在于:
-
减少资源消耗:避免重复创建数据库连接、缓存实例、日志工具等资源密集型对象;
-
保证数据一致性:全局唯一实例可确保共享状态(如配置信息)的一致性;
-
简化全局访问:无需频繁通过参数传递对象,通过固定方法即可获取实例。
代码
<?php
declare(strict_types = 1);
/**
* 单例模式:保证类仅有一个实例,并提供全局访问点
* Class SingleObject
* @package Extend
*/
class SingleObject
{
// 1. 私有静态属性:存储唯一实例(添加 readonly 限制,避免外部篡改)
private static readonly ?self $instance = null;
// 2. 私有构造方法:禁止类外通过 new 实例化
private function __construct()
{
// 可选:添加初始化逻辑(如连接数据库、加载配置)
// $this->init();
}
// 3. 私有克隆方法:禁止类外通过 clone 复制实例
private function __clone() {}
// 4. 禁止序列化:避免通过反序列化创建新实例
private function __wakeup() {}
// 5. 公有静态方法:获取唯一实例(添加 final 防止子类重写,确保单例逻辑不被破坏)
public static final function getInstance(): self
{
// 双重检查锁定(DCL):解决多线程/并发场景下的实例重复创建问题
if (is_null(self::$instance)) {
// 加锁:阻止并发请求同时进入实例化逻辑
synchronized(function () {
if (is_null(self::$instance)) {
self::$instance = new self();
}
});
}
return self::$instance;
}
// 示例:单例类的业务方法
public function doSomething(): string
{
return "单例对象执行业务逻辑";
}
}
// 测试代码
$obj1 = SingleObject::getInstance();
$obj2 = SingleObject::getInstance();
// 验证是否为同一实例(输出 bool(true))
var_dump($obj1 === $obj2);
// 调用业务方法(输出 string(24) "单例对象执行业务逻辑")
echo $obj1->doSomething();
说明
-
并发安全:
-
上述代码中
synchronized()是 PHP 8.1+ 提供的内置函数,用于实现互斥锁; -
若使用 PHP 8.1 以下版本,可通过
Mutex扩展或自定义锁机制(如文件锁、Redis 锁)替代。
-
-
反射攻击防护:
- 原文代码未防护反射攻击(通过反射调用私有构造方法),若需严格防护,可在构造方法中添加判断:
private function __construct() { if (!is_null(self::$instance)) { throw new \RuntimeException("单例类不允许重复实例化"); } }
- 原文代码未防护反射攻击(通过反射调用私有构造方法),若需严格防护,可在构造方法中添加判断:
-
适用场景:
- 该单例模式适用于数据库连接、缓存服务、日志工具、配置管理等需要全局唯一实例的场景;
- 避免在简单脚本或无共享状态的场景中过度使用单例,否则会增加代码耦合度。


