单例模式
先看场景:
多人协同开发,都要调用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 "我要出国,做美利坚人";
}
}