2018-3-6 对象的继承
对象继承:
类A具有某些特征,类B也具有A类的所有特征,同时具有自己更多的一些特征,此时发现,B类使用A的特征信息并继续添加自己的一些特有特征信息。我们可以说B类继承于A类。
class jizuidongwu{ public $prop1 = "有脊椎"; function show1(){ echo "<br />特征:" . $this->prop1; } } class human extends jizuidongwu{ //human继承于jizuidongwu public $prop2 = "两脚走路"; function show2(){ echo "<br />特征:" . $this->prop2; } } $person1 = new human(); $person1->show1(); //$person1是human的对象,但可以执行jizuidongwu的方法 $person1->show2();
概念:
继承:一个类从另一个已有的类获得属性,称为继承。
派生:从一个已有的类产生一个新的类,称为派生。
父类/子类:已有类为父类,新建类为子类。父类也叫“基类”,子类也叫“派生类”
单继承:一个类只能从一个上级类继承其特性信息。PHP和大多数面向对象的语言都是单继承模式。C++是多继承。
访问(权限)修饰符:
在类中的成员,通常都可以在前面加上以下3个修饰符:
public:公共的,共有的,公开的
protected:受保护的
private:私有的
访问位置:
1、private某个类的内部;
class C{ private $p1 = 1; public function showInfo(){ echo "<br />属性p1=" . $this->p1; } } class D extends C{ private $p2 = 2; public function showInfo2(){ echo "<br />属性p1=" . $this->p1;//访问的是上级的似有成员$p1 echo "<br />属性p2=" . $this->p2;//访问的是自己的私有成员$p1 } } $d1 = new D(); $d1->showInfo2(); echo "<br />在类外p2=" . $d1->p2;//这一行出错,因为在“外面”不能访问私有成员$p2
2、protected某个类及其子类的内部;
class C{ protected $p1 = 1; public function showInfo(){ echo "<br />属性p1=" . $this->p1; } } class D extends C{ protected $p2 = 2; public function showInfo2(){ echo "<br />属性p1=" . $this->p1;//访问的是上级的受保护成员$p1 echo "<br />属性p2=" . $this->p2;//访问的是自己的受保护成员$p1 } } $d1 = new D(); $d1->showInfo2(); echo "<br />在类外p2=" . $d1->p2;//这一行出错,因为在“外面”不能访问受保护成员$p2
3、public所有位置,内部和外部都可以使用;
class C{ public $p1 = 1; public function showInfo(){ echo "<br />属性p1=" . $this->p1; echo "<br />属性p2=" . $this->p2;//此时可以访问下级的$p2(但很不常用) } } class D extends C{ //D继承于C public $p2 = 2; public function showInfo2(){ echo "<br />属性p1=" . $this->p1;//访问的是上级的$p1(常见情形) echo "<br />属性p2=" . $this->p2; } } $d1 = new D(); $d1->showInfo2(); echo "<br />在类外p2=" . $d1->p2; //说明在类外也可以调用public $p2 = 2; $d1->showInfo();
此时输出结果为:
属性p1=1
属性p2=2
在类外p2=2
属性p1=1
属性p2=2
总结以上,访问修饰限定符的使用范围:
范围 |
本类内 |
继承关系类内 |
类外 |
public |
可以 |
可以 |
可以 |
protected |
可以 |
可以 |
不可以 |
private |
可以 |
不可以 |
不可以 |
parent代表父类:
self代表“本类”;
parent通常用于在子类中调用父类的成员的时候使用,多数通常就是使用父类的“静态类”成员。
class C{ public $p1 = 1; function showMe(){ echo "<br />我是父类,数据有:"; echo "<br />C中p1=" . $this->p1; } function __construct($p1){ $this->p1 = $p1; } } class D extends C{ public $p2 = 2; function __construct($p1,$p2){ //经典用法 parent::__construct($p1);//调用父类的构造函数来初始化p1 $this->p2 = $p2; //初始化p2 } function showMe2(){ echo "<br />我是子类,数据有:"; //基本用法: parent::showMe(); //调用父类的showMe方法, echo "<br />D中p2=" . $this->p2; } } $d1 = new D(10,20); //此时就需要尊照构造函数的参数结构来使用 $d1->showMe2();
构造方法和析构方法在继承中的表现:
子类中没有定义构造方法时,会自动调用父类的构造方法。因此实例化子类时,需按照父类的构造方法的形式进行。
class C{ public $p1 = 1; public $p3 = 3; function __construct($p1,$p3){ //设置父类的构造方法 echo "<br />父类构造方法调用了"; $this->p1 = $p1; $this->p3 = $p3; } } class D extends C{ public $p2 = 2; function __construct($p1,$p2, $p3){ //设置子类的构造方法 echo "<br />子类构造方法调用了"; parent::__construct($p1,$p3); //调用父类构造方法 $this->p2 = $p2; } function showInfo(){ //方法名 echo "<br />p1=$this->p1"; echo "<br />p2=$this->p2"; echo "<br />p3=$this->p3"; } } $d1 = new D(10, 20, 30); //新建对象$d1 $d1->showInfo(); //调用方法
很多时候,在构造方法中,子类都可以通过调用父类的构造方法节省代码,增加可读性。
当子类定义了自己的析构方法后,则就不会自动调用父类的析构方法的,但可以手动调用:parent::__destruct()
重写:
重写又叫覆盖,将从父类继承下来的属性或方法重新“定义”。重写发生在父类底下的子类中。
class Jizhuidongwu{ public $p1 = "具有脊椎"; function showMe(){ //父类方法 echo "<br />我是脊椎动物,特征为:"; echo "<br />属性p1=" . $this->p1; } } class Human extends Jizhuidongwu{ public $p1 = "具有28节脊椎骨的脊椎";//28是假设 public $p2 = '有32颗牙齿'; function showMe(){ //重写方法 echo "<br />我是人类,特征为:"; //echo "<br />属性p1:" . $this->p1; //实际应用中,通常上一行(显示父类信息)会使用下一行代替 parent::showMe(); //这样可以更节省 echo "<br />属性p2:" . $this->p2; } } $h1 = new Human(); $h1->showMe();
重写具有一定的要求,主要就是访问权限以及参数。
访问权限方面,下级的访问权限应不低于上级的访问权限。
上级:public 下级:只能public
上级:protected 下级: protected, public
上级:private 下级:private protected public——实际此情况无意义。
方法的参数形式应该与父类的保持一致。
构造方法在重写的时候参数可以不一致。
最终类final class:
最终类不会再继续往下拓展,即这就是最底下的类,可以定义对象,不能有子类。
形式:final class 类名{ 类定义 }
最终方法 final method:这个方法不会被下级类覆盖。
final function 方法名(){ 方法定义 }
设计模式:解决问题的常用做法,比较好的经验总结。针对不同问题,有不同的解决办法,这就是不同的设计模式。
工厂模式:有时候,我们需要实例化许多类,用来得到对象。
设计一个“工厂”(类)作用是“生产”各种对象。通常这种工厂,只需要制定类名,就可以获取一个该类的对象。
class factory{ //Instance表示“实例”,“对象” static function getInstance($className){ if(file_exists('./class/' . $className . ".class.php")){ $obj1 = new $className(); return $obj1; } else{ return null;//也可以die(); } } } $obj1 = factory::getInstance("A");//获取类A的一个对象 $obj2 = factory::getInstance("B");//获取类B的一个对象 $obj3 = factory::getInstance("A");//再获取类A的一个对象