【设计模式】单例模式(php实现)

为什么要使用单例模式

php中有哪些方式实现新建一个对象实例

  • 通过new实例化对象
  • 通过clone复制对象
  • 通过序列化反序列化得到对象实例
  • 通过类的反射实例化对象

如何阻止这种实例化实现理想的单例模式

1. new test();//通过new实例化对象	: 通过更改构造方法为private 阻止使用方直接new 对象 	
3. 通过clone复制对象 : 通过定义private __clone()阻止复制操作 
4. 通过序列化反序列化得到对象实例 :通过定义__wakeup()阻止对象的反序列化。
5. 通过类的反射实例化对象:暂时还没有相应的方法去阻止使用此方法实现对象多例

代码实现

<?php
/**
 * Created by PhpStorm.
 * User: Uasier
 * Date: 2018/10/17
 * Time: 15:10
 */

/**
 * 单例模式实例
 */
class Singleton
{
    /**
     * 私有变量存实例
     * @var Singleton
     */
    private static $instance;

    /**
     * 私有构造函数
     * Singleton constructor.
     */
    private function __construct()
    {
        var_dump('构造了对象');
    }

    /**
     * clone 魔术方法
     */
    private function __clone()
    {
        var_dump('复制了对象');
    }

    /**
     * sleep 魔术方法
     * @return array
     */
    public function  __sleep(){
        //todo 如何阻止
        var_dump('序列化了对象');
        return [];
    }

    /**
     * wakeup 魔术方法
     */
    public function  __wakeup(){
        //todo 如何阻止
        var_dump('反序列化了对象');
    }

    /**
     * 公有获取实例方法
     * @return Singleton
     */
    public static function getInstance()
    {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        var_dump('返回了对象');
        return self::$instance;
    }
}

//*******************************单例模式测试****************************
//①在Singleton没有实例的情况下获取实例
$a = Singleton::getInstance();
var_dump($a);

//在Singleton已经有实例的情况下获取实例
$b = Singleton::getInstance();
var_dump($b);

//②通过克隆来得到实例
$c = clone $a;
var_dump($c);

//③通过序列化再反序列化得到实例
$d = serialize($a);//序列化
$e = unserialize($d);//反序列化
$e->name = '反序列化';
var_dump($e);

//④php 反射来的到实例
$obj = new ReflectionObject('Singleton');
$f = $obj->newInstanceWithoutConstructor();
var_dump($f);

讨论

相对而言,php中四种实例对象的方式,但是我们能(合理)阻止的只有3种,
如代码体现的,php的反射来获得实例是我们阻止不了的一种方式(然而java却可以),
但是怎么说呢,php 的反射也不是为了让你去破解单例模式的,
简而言之,我们其实不用舍本求末过分追求单例模式的完美性,毕竟实现单例模式的是程序员,使用单例模式的也是程序员。程序员使用反射来创建一个新的对象时,也就表示了,这确实需要一个新的对象了