PHP单例模式使用clone

Posted jfcat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP单例模式使用clone相关的知识,希望对你有一定的参考价值。

我们来看下php单例模式是否能够clone,先上一段代码。

<?php
class Singleton {
    private static $object;
    private $name;

    private function __construct(string $name) {
        $this->name= $name;
    }

    public static function getInstance(string $name) {
        if (self::$object == null) {
            $object = new Singleton($name);
        }
        return $object;
    }
}

这是一个单例模式的简单实现,构造函数是private访问修饰符,所以不能直接调用,例如这样new一个会报错:

$c = new Singleton("c");

加上如上代码执行会报错,
~/Develop/PHP/test  php singleton.php PHP Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context in /Users/mark/Develop/PHP/test/singleton.php:23 Stack trace: #0 {main} thrown in /Users/mark/Develop/PHP/test/singleton.php on line 23

我们通过提供getInstance()静态方法来实现实例化,并保证实例只有一个。如果我们再加上clone会怎么样呢,继续看代码:

$c = new Singleton("c");
$a = Singleton::getInstance("a");
$b = clone $a;

var_dump($a);
var_dump($b);

代码执行的结果是这样的,

object(Singleton)#1 (1) {
  ["name":"Singleton":private]=>
  string(1) "a"
}
object(Singleton)#2 (1) {
  ["name":"Singleton":private]=>
  string(1) "a"
}

对象就是对象,模式只是人为的控制,看下官方对对象复制的描述

对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。

$copy_of_object = clone $object; 当对象被复制后,PHP 5
会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。

__clone(): void 当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。

然后我们再增加__clone方法做下实验,

    public function __clone() {
        $this->name = "clone";
    }

再次执行代码,

object(Singleton)#1 (1) {
  ["name":"Singleton":private]=>
  string(1) "a"
}
object(Singleton)#2 (1) {
  ["name":"Singleton":private]=>
  string(5) "clone"
}

返回的结果证明对象clone是成功的,但是这样不符合单例模式的要求,那么如何禁止单例模式下的clone呢,根据php官方的文档,我们知道__clone会在克隆操作完成后被调用,要能够被调用就必须是public访问修饰符,如果改为private,这个方法就不能被调用了,示例如下:

    private function __clone() {
        $this->name = "clone";
    }

再次执行代码,得到以下报错:

PHP Fatal error:  Uncaught Error: Call to private Singleton::__clone() from context '' in /Users/mark/Develop/PHP/test/singleton.php:24
Stack trace:
#0 {main}
  thrown in /Users/mark/Develop/PHP/test/singleton.php on line 24

证明在调用__clone方法时出错了,这样可以来禁止单例的clone

参考:
https://www.php.net/manual/zh/language.oop5.cloning.php

以上是关于PHP单例模式使用clone的主要内容,如果未能解决你的问题,请参考以下文章

PHP设计模式

php 模式设计之单例模式

PHP设计模式-单例模式

php 单例模式

PHP 单例模式

PHP中设计模式以及魔术方法