继承: 是指以一个类为父类,另一个类可以做为其子类,
子类在继承了父类的属性/方法的基础上,进一步增添或修改.
引出继承概念
// 定义3个类, 人类, 学生类,律师类
class Human {
private $height = 160;
public function cry() {
echo '5555<br />';
}
}
class Stu {
private $height = 170;
public $snun = '00134';
public function cry() {
echo '59啊59....<br />';
}
public function study() {
echo 'good good study, day day up<br />';
}
}
class Lawer {
private $height = '180';
public $area = '经济案件';
public function cry() {
echo '5555<br />';
}
public function bianhu() {
echo '我的当事人是无罪的<br />';
}
}
$zhoukou = new Human();
$zhoukou->cry();
$xiaoming = new Stu();
$xiaoming->cry();
$xiaoming->study();
$lizhuang = new Lawer();
$lizhuang->cry();
$lizhuang->bianhu();
/**
1: 学生和律师 归根结底还是人!
自然,人的属性和方法,自然就有
2:学生和律师,虽然是人,但比最原始的人,
又多了一些属性和方法.
而我们目前写的3个类,
完成了第2点: 即有原始人的属性,又有学生/律师的独特属性
但是,没有很好的利用上第1点:
即:既然是人,那默认就应该有人的属性,何必再重新声明一遍???
这里的代码,就已经冗余!
如何达到 学生/律师 默认就有人的属性,达到代码的重用和简洁?
答: 继承
语法:
子类 extends 父类 {
}
注意点: 子类 只能继承自 一个父类
简单的继承示例
class Human {
private $height = 160;
public function cry() {
echo '5555<br />';
}
}
// 再声明一个学生类,学生本质上还是人
// 只不过是人类中,稍微特殊一点的一个群体.
// 即:人类的基础上,衍生出学生类.
// 可以让学生类 继承自 人类
class Stu extends Human{
}
$zhoukou = new Human();
$zhoukou->cry();
/**/
$lily = new Stu();
$lily->cry();
$lily->laugh();
/*
思考:
在学生类中
cry 与 laugh方法 都没定义
为什么cry方法调用成功
laugh方法调用失败!
答:因为Stu类 继承自 Human类
现实中,继承的例子更多.
你同事高帅富,某天开了个宝马.
他没有宝马,但是他爹有宝马.
继承的范围
继承了哪些东西?
子类可以做什么扩充? 构造函数如何继承的? 私有属性/方法如何继承?
class Human {
private $wife = '小甜甜';
public function cry() {
echo '5555<br />';
}
}
class Stu extends Human{
public function subtell() {
echo $this->wife;
}
}
$lisi = new Stu();
$lisi->cry(); // 5555
$lisi->subtell(); // 出错:未定义的属性,wife属性Undefined property: Stu::$wife in 。。。
/**
问:父类不是有wife属性吗? 为什么没继承过来?
答: 私有的属性,可以理解不能继承.
(其实能继承过来,只不过无法访问)
public protected private中,
public protected 都可以继承,并拥有访问和修改的权限
这就好比说,家产已经继承了,愿意卖就卖,愿意改就改.
而私有的,就像先祖的牌位,继承下来
但是无权动,只能供着.
举例:
class Human {
private $wife = '小甜甜';
public $age = 22;
public function cry() {
echo '5555<br />';
}
public function pshow() {
echo $this->wife,'<br />';
}
}
class Stu extends Human{
private $wife = '凤姐';
public $height = 180;
public function sshow() {
parent::pshow();
echo $this->wife,'<br />';
}
}
$lisi = new Stu();
$lisi->sshow();
/**最后一句中:思考?
如果把Stu类中的 wife=凤姐去掉,什么效果? // echo $this->wife 出错;未定义属性Undefined property: Stu::$wife
如果把Human类中的 wife=小甜甜去掉,什么效果? // parent::pshow() 出错;无权访问Cannot access private property Stu::$wife
子类继承父类的属性/方法,可以修改或增加
这里所说的继承过来的大环境,是指 protected /public
class sixty {
protected $wine = '1斤';
public function play() {
echo '谈理想<br />';
}
}
class nine extends sixty{
public function play() {
echo '玩网游,宅!<br />';
}
public function momo() {
echo '妹子,认识一下<br />';
}
public function showW() {
echo $this->wine,'<br />';
}
}
$s9 = new nine();
$s9->showW(); echo '<br />'; // 父类有的,继承过来
$s9->play(); // 父类有的,继承过来,可以修改/覆盖(overide).
$s9->momo(); // 父类没有,可以添加
继承的权限变化
继承自父类的属性/方法
权限只能越来越宽松或不变,不能越来越严格.
class Human {
public function cry() {
echo '555<br />';
}
}
class Stu extends Human{
protected function cry() {
echo '5959<br />';
}
}
/**
Fatal error: Access level to Stu::cry() must be public (as in class Human) in 。。。
子类的cry比父类的cry方法,权限要严格.
这不行,继承时,权限只能越来越宽松或不变,不能越来越严格.
构造方法的继承
构造方法也是可以继承的,而且继承的原则和普通方法一样.
如果子类也声明构造函数,则父类的构造函数,被覆盖了!如果父类构造函数被覆盖了,自然,只执行子类中新的构造函数.
class Human {
public function __construct(){
echo '呱呱坠地!<br />';
}
}
class Stu extends Human {
}
$ming = new Stu(); // 呱呱坠地,这说明构造函数也是可以继承的
class King extends Human {
public function __construct() {
echo '红光满屋,终日不散<br />';
}
}
$king=new King(); //'红光满屋,终日不散 ,父类的构造函数已经被覆盖
引发一个问题:
如果是一个数据库操作类,或者model类我们肯定是要继承过去再使用,不能直接操作model类.
而model类的构造函数,又做了许多初始化工作.
我重写的model类的构造函数之后,导致初始化工作完不成了,怎么办?
答: 如果子类继承时,子类有构造函数,保险一点,调用 parent::__construct
class Mysql {
protected $conn = NULL;
public function __construct() {
$this->conn = mysql_connect('localhost','root','111111');
}
public function query($sql) {
return mysql_query($sql,$this->conn);
}
}
class MyDb extends Mysql{
public function __construct() {
// 如果子类继承时,有构造函数,保险一点
parent::__construct();
// 然后再写自己的业务逻辑
}
public function autoInsert() {
return $this->query('use test');
}
}
和java的不同
这一点和java的面向对象,也有不同.
在java中,实例化子类时, 父类的构造函数运行,且先运行然后运行子类的构造函数
java中构造函数不是 __construct(),而是和类名相同的方法理解为构造函数
public class ExtTest
{
public static void main (String[] args)
{
Stu ming = new Stu();
}
}
class Human
{
Human ()
{
System.out.println("Human");
}
}
class Stu extends Human
{
Stu()
{
System.out.println("Stu");
}
}
/**
Human
Stu
说明,父类,子类构造函数,先后调用
而在PHP中,只调用子类自己的,或子类继承的构造函数