PHP面向对象 —— 19 单例模式

// 如何限制多人开发时只得到一个对象?

// 单例模式常用也常考,注意练习

/*
第一步:

一个普通类放在这,就可以new 来实例化,
也可new多次 得到多个对象

就不是单例了.
*/

/*
第二步:

那么如何不让类new呢?

我们用构造方法 保护/私有化
外部就不能new了

然而,不能new就得不到对象,
又不是单例了,是没例.
*/

class single { 
	protected function __construct() {
		
	}
	
	public function getInstance() {
		return new self();
	}
}

$s1 = new single(); //报错

/*
Fatal error: Call to protected single::__construct() from invalid context 
报错:你在调用一个受保护的construct
*/

/*
第三步:

我们可以通过内部的static方法来调用.

static不依赖于对象,所以可以直接调用.
*/

class single2 {
	public $hash; // public 一个随机码
	
	protected function __construct() {
		$this->hash = mt_rand(1,99999);
	}
	
	static public function getInstance() {
		return new self();
	}
}

$s1 = single2::getInstance();
$s2 = single2::getInstance();
/*
两个对象什么时间相等?
只有指向同一个对象的地址的时候,才相等.
*/

print_r($s1);
print_r($s2);


if($s1 == $s2) {
	echo '是一个对象';
} else {
	echo '不是一个对象';
}
/*
single2 Object
(
    [hash] => 42633
)
single2 Object
(
    [hash] => 95744
)
不是一个对象
*/

echo '<hr >';

/*
第四步:

通过内部的static方法实例化.
并把实例保存在类内部的静态属性上.
*/

class single3 {
	public $hash; // public 一个随机码
	
	static protected $ins = null;
	
	protected function __construct() {
		$this->hash = mt_rand(1,99999);
	}
	
	static public function getInstance() {
		if(self::$ins instanceof self) {
		// instance示例 of谁的
        // 专门判断某个对象是不是某个类的实例 用的		
		    return self::$ins;
			
		}
		
		self::$ins = new self();
		return self::$ins;
	}
}

$s1 = single3::getInstance();
$s2 = single3::getInstance();


print_r($s1);
print_r($s2);


if($s1 == $s2) {
	echo '是一个对象';
} else {
	echo '不是一个对象';
}
/*
single3 Object
(
    [hash] => 11410
)
single3 Object
(
    [hash] => 11410
)
是一个对象
*/


// 看问题 //
/*
我们的目的是让其成为同一个对象,
然而此时继承过来的改写后还能否是同一个对象?
*/

class test extends single3 {
	public function __construct() {
		parent::__construct();
	}
}

$t1 = new test();
$t2 = new test();


print_r($t1);
print_r($t2);


if($t1 == $t2) {
	echo '是一个对象';
} else {
	echo '不是一个对象';
}
/*
test Object
(
    [hash] => 99116
)
test Object
(
    [hash] => 19702
)
不是一个对象
*/


// 解决问题 //
/*
我们写出的单例继承了一下就不灵了,那么如何解决呢?
答:可以用final.

在PHP中,final 可以修改类,方法名,但不能修改属性.

在Java中,final 可以修改属性,此时属性值,就是一个常量,不可修改.
*/

// final修改方法,此方法不影响继承,但是此方法不允许重写.

/*
final class Human {
	
}

class Stu extends Human {
	
}

报错如下:不能继承自最终的类
Fatal error: Class Stu may not inherit from final class (Human) 
*/


class Human {
	final public function say() {
		echo '华夏子孙';
	}
	
	public function show() {
		echo '哈哈';
	}
}


class Stu extends Human {
	
}

$ming = new Stu;
$ming->say();


/*
class FreshMan extends Stu {
	public function say() {
		echo '我要出国';
	}
}

报错如下:不能覆盖父类原有的say方法
Fatal error: Cannot override final method Human::say() 
*/


/*
第五步:

运用final
解决被继承后单例就失灵的问题.
*/

class single4 {
	public $hash; // public 一个随机码
	
	static protected $ins = null;
	
	final protected function __construct() {
		$this->hash = mt_rand(1,99999);
	}
	
	static public function getInstance() {
		if(self::$ins instanceof self) {
		// instance示例 of谁的
        // 专门判断某个对象是不是某个类的实例 用的		
		    return self::$ins;
			
		}
		
		self::$ins = new self();
		return self::$ins;
	}
}


/*
class test extends single4 {
	public function __construct() {
		parent::__construct();
	}
}

$t1 = new test();
$t2 = new test();

报错如下:不能覆盖父类single4原有的__construct方法
Fatal error: Cannot override final method single4::__construct()
*/


class test2 extends single4 {
	
}

$t1 = test2::getInstance();
$t2 = test2::getInstance();


print_r($t1);
print_r($t2);


if($t1 == $t2) {
	echo '是一个对象';
} else {
	echo '不是一个对象';
}
/*
single4 Object
(
    [hash] => 44041
)
single4 Object
(
    [hash] => 44041
)
是一个对象
*/


// clone魔术方法

$t3 = clone $t2;

if($t3 == $t2) {
	echo '是一个对象<br >';
} else {
	echo '不是一个对象<br >';
} // 是一个对象


if($t3 === $t2) {
	echo '是一个对象<br >';
} else {
	echo '不是一个对象<br >';
} // 不是一个对象

// 此时我们发现即使是克隆过来的,在严格相等情况下,也不是一个对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟敛寒林o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值