单例模式

先看场景:
多人协同开发,都要调用mysql类的实例
如果用svn的,知道好多人一起开发,再提交各自的文件

开发者A:
$mysql = new mysqli();
$mysql->query...
测试通过

开发者B:
$db = new mysqli();
测试通过
...
...

两人的代码要合到一块,如下

  • $mysql = new mysqli();
  • $mysql->query...
  • $db = new mysqli();

两个mysql类的实例,
而且,没new一下,还要链接一下数据库

显然,一个页面呢,有一个mysql类的实例就够了

如果限制,让多人开发,无论你怎么操作,只能得到一个对象?
1.开会时,经理说:有一个$db变量,是系统自动初始化的,就是mysql类的实例
大家都用它,谁敢new mysql(),开除
2.这种行政上的手段,不能阻止技术上的new mysql()行为
我们可以从技术上用单例模式来解决

第一步:一个普通的类

这个普通的类,可以new实例化
这显然不是单例

<?php
class single{

}

$s1 = new single();
$s2 = new single();
$s3 = new single();

第二步: 看来new是罪恶之源,干脆不让new了

我们把构造方法 保护/私有

外部不能new了,
但是引出一个问题,不能new,就得不到对象,这不是单例,
而是0例模式

class single{
	protected function __construct(){

	}
}

$s1 = new single();

第三步:通过内部的 static 方法,来调用

class single{
	public $hash;//随机码
	protected function __construct(){
		$this->hash = mt_rand(1,99999);
	}

	static public function getInstance(){
		return new self();
	}
}

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


// 两个对象什么时间相等?
// 答:只有指向一个对象地址的时候,才相等.

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

if ($s1 === $s2) {
	echo "是同一个对象";
} else {
	echo "不是同一个对象";
}

第四步:通过内部的 static 方法,来实例化,

并且,把实例保存在类内部的静态属性上

class single{
    public $hash;//随机码

    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 = single::getInstance();
$s2 = single::getInstance();

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

if ($s1 == $s2) {
	echo "是同一个对象";
} else {
	echo "不是同一个对象";
}


//=======看问题===========//

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

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

print_r($t1);
print_r($t2);
//问题1: 我们辛苦写的一个类,继承下就不灵了
//答:使用final,见496danlimodel2.php


class s{
	public $hash;//随机码

	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 t extends s{

}


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

$t3 = clone $t2;

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

//clone又多出一个对象,试问,如何解决?
//提示:请看魔术方法 clone!
//魔术方法很多,__construct,__destruct,__clone,__callstatic

final关键字

final 最终的
这个关键词 在php中可以修饰类,方法名,但不能修饰属性
final 修饰类,则此类不能被继承
final 修饰方法,此方法不影响继承,但是不可重写

在java中,final也可以修饰属性,此时属性值就是一个常量,不可修改

问:php的类中,可不可以有常量
答:有

<?php
final class Human{

}

class Stu extends Human{

}

上面是不能继承最终的类,会报错
Fatal error: Class Stu may not inherit from final class (Human) in D:\wamp2\www\PHPoop\496danlimodel2.php on line 20

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

	public function show(){
		echo "haha";
	}
}

class Stu extends Human{

}

$ming = new Stu();
$ming->say(); //final 方法可以继承

class FreshMan extends Stu{
	public function say(){
		echo "我要出国,做美利坚人";
	}
}