php面向對象之繼承

繼承: 是指以一個類爲父類,另一個類可以做爲其子類,
子類在繼承了父類的屬性/方法的基礎上,進一步增添或修改.

引出繼承概念

// 定義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中,只調用子類自己的,或子類繼承的構造函數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章