php设计模式-单例模式
<?php
//简单的单例
class Singleleton {
private static $_instance = null;
public static function getSingleleton()
{
if (isset(self::$_instance)) {
return self::$_instance;
}
return new self();
}
}
$instance1 = new Singleleton();
$instance2 = Singleleton::getSingleleton();
// var_dump($instance1);
// var_dump($instance2);
/*
结果:object(Singleleton)#1 (0) { } object(Singleleton)#2 (0) { }
问题:不能防止new实例化
*/
// 改进1:封锁new 操作
class Singleleton_1 {
protected static $_instance = null; // 把自己的实例放在自己的一个静态属性上
public static function getSingleleton()
{
if (isset(self::$_instance)) {
return self::$_instance;
}
return new self();
}
protected function __construct(){}
}
// $instance1 = new Singleleton_1();
// $instance2 = Singleleton_1::getSingleleton();
// var_dump($instance1);
// var_dump($instance2);
/*
结果:Fatal error: Uncaught Error: Call to protected Singleleton_1::__construct() from invalid context
结论:将构造方法设置为受保护阻止以new形式格式化
问题: 一个类继承该类,并且使用public修饰的构造方法覆盖了父方法,则封锁__construct失败
*/
class Child extends Singleleton_1
{
public function __construct()
{
}
}
$ins1 = new Child;
$ins2 = new Child;
// 这里用== 会得到true, 所以用===
echo $ins1 === $ins2 ? '同一个实例' : '不同实例';
/*
结果:不同实例
*/
// 改进2:使用final禁止覆盖构造方法
class Singleleton_2 {
protected static $_instance = null; // 把自己的实例放在自己的一个静态属性上
public static function getSingleleton()
{
if (isset(self::$_instance)) {
return self::$_instance;
}
return new self();
}
// 当方法加final修饰,表示继承不能被覆盖,类加final表示不能被继承
protected final function __construct(){}
}
// class Child_2 extends Singleleton_2
// {
// public function __construct()
// {
// }
// }
/**
* 结果:Fatal error: Cannot override final method Singleleton_2::__construct()
* 结论:能防止方法覆盖,导致单例失效
* 问题:不能防止克隆,导致不同实例
*/
// 改进3: 防止克隆
class Singleleton_3 {
protected static $_instance = null; // 把自己的实例放在自己的一个静态属性上
public static function getSingleleton()
{
if (isset(self::$_instance)) {
return self::$_instance;
}
return new self();
}
// 当方法加final修饰,表示继承不能被覆盖,类加final表示不能被继承
protected final function __construct(){}
}
$ins1 = Singleleton_3::getSingleleton();
$ins2 = clone $ins1;
echo $ins1 === $ins2 ? '同一个实例' : '不同实例'; // 不同实例
class Singleleton_4 {
protected static $_instance = null; // 把自己的实例放在自己的一个静态属性上
public static function getSingleleton()
{
if (isset(self::$_instance)) {
return self::$_instance;
}
return new self();
}
// 当方法加final修饰,表示继承不能被覆盖,类加final表示不能被继承
protected final function __construct(){}
// 封锁克隆
protected final function __clone(){}
}
$ins1 = Singleleton_4::getSingleleton(); //Fatal error: Uncaught Error: Call to protected Singleleton_4::__clone() from context
$ins2 = clone $ins1;
/**
* 结论:可以将父克隆方法设置受保护final修饰,则实例不能被克隆
*/
总结:单例模式原理是防止类被外部实例化,通过保护类的构造方法,并在类内部通过静态方式实例化来达到单例效果,一个完善单例模式应该满足一下几点
- 类构造方法受保护,且final修饰,保证不能被外部实例化或子类覆写构造方法进行外部实例化
- 类克隆方法受保护,且finals修饰,保证不能被克隆


浙公网安备 33010602011771号