php单例模式怎么正确使用

PHP单例模式是一种设计模式,它确保整个应用中某个类只有一个对象实例。在PHP中,可以使用三种方式实现单例模式:懒汉式单例、饿汉式单例和登记式单例。懒汉式单例是在第一次调用时实例化对象,而饿汉式单例是在类加载时就实例化对象。登记式单例是通过在配置文件中保存一个唯一的实例标识来实现的 。

单例模式简介

单例模式是一种设计模式,它保证一个类仅有一个实例,并提供一个全局访问点,在PHP中,我们可以通过以下几种方式实现单例模式:

1、懒汉式(线程安全)

php单例模式怎么正确使用

2、饿汉式

3、双重检查锁定(DCL)

4、静态内部类

php单例模式怎么正确使用

懒汉式(线程安全)

懒汉式单例模式是在第一次请求时实例化对象,这种方式简单易懂,但可能会导致线程安全问题,下面是一个简单的懒汉式单例模式实现:

class Singleton
{
    private static $instance;
    private function __construct() {}
    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

饿汉式

饿汉式单例模式是在程序启动时就实例化对象,这样可以避免多线程环境下的线程安全问题,由于对象在程序启动时就已经创建,可能导致资源浪费,下面是一个简单的饿汉式单例模式实现:

class Singleton
{
    private static $instance = new self();
    private function __construct() {}
    public static function getInstance()
    {
        return self::$instance;
    }
}

双重检查锁定(DCL)

双重检查锁定是一种线程安全的单例模式实现方式,它在懒汉式的基础上增加了一层检查锁定机制,确保只有一个实例被创建,下面是一个简单的双重检查锁定单例模式实现:

php单例模式怎么正确使用

class Singleton
{
    private static $instance = null;
    private static $lock = false;
    private function __construct() {}
    public static function getInstance()
    {
        if (!self::$lock && null === self::$instance) {
            self::$lock = true;
            self::$instance = new self();
        } elseif (self::$lock && null !== self::$instance) {
            self::$instance->__clone(); // 防止克隆导致的内存泄漏问题
        } elseif (null !== self::$instance) { // 防止多个非线程安全的getInstance()调用同时执行到这一句,导致实例重复创建或未创建的情况发生,注意这里不能使用++操作符,因为它不是原子操作,这个判断条件要放在最前面,否则在多线程环境下可能会出现问题,具体请参考下面的示例代码,为了防止循环引用导致内存泄漏,可以使用SplObjectStorage来存储已经创建的实例,下面是一个简单的双重检查锁定单例模式实现:

class SplSingleton implements \IteratorAggregate, \ArrayAccess, \Countable, Serializable{//接口定义就不写了,具体可自行查阅相关资料,这里需要注意的是,如果要让SplSingleton支持序列化和反序列化操作,那么需要重载Serializable接口的serialize()和unserialize()方法,由于实现了IteratorAggregate、ArrayAccess、Countable三个接口,所以也可以使用foreach、offsetExists、count等数组相关的函数,最后是iterator(),这个函数返回一个迭代器对象,用于遍历SplSingleton中的元素,下面是一个简单的双重检查锁定单例模式实现:function __construct(){//构造函数私有化,防止外部直接创建实例,if(null===$this->instance){//加锁判断是否已经创建过实例if(!static::$lock){//加锁static::$lock=true;//加锁操作try{//加锁执行创建实例的操作$this->instance=new static();}finally{//无论是否成功都释放锁static::$lock=false;}}}}else{//如果已经存在实例,则克隆一份新的实例给当前实例$this->instance=$this->instance->__clone();}}public function __clone(){//禁止克隆function __clone(){throw new \Exception('不允许克隆');}}public function rewind(){//重置指针function rewind(){throw new \Exception('不允许重置指针');}}public function current(){//获取当前元素function current(){return $this->instance;}}public function key(){//获取键名function key(){return null;}}public function next(){//获取下一个元素function next(){throw new \Exception('不允许获取下一个元素');}}public function valid(){//判断是否还有下一个元素function valid(){return true;}}public function getIterator(){//返回迭代器对象return new ArrayIterator([$this->instance]);}}?>```

原创文章,作者:K-seo,如若转载,请注明出处:https://www.kdun.cn/ask/260371.html

(0)
K-seoK-seoSEO优化员
上一篇 2024年1月25日 06:54
下一篇 2024年1月25日 06:56

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

免备案 高防CDN 无视CC/DDOS攻击 限时秒杀,10元即可体验  (专业解决各类攻击)>>点击进入