// 如何限制多人开发时只得到一个对象?
// 单例模式常用也常考,注意练习
/*
第一步:
一个普通类放在这,就可以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 >';
} // 不是一个对象
// 此时我们发现即使是克隆过来的,在严格相等情况下,也不是一个对象