繼承: 是指以一個類爲父類,另一個類可以做爲其子類,
子類在繼承了父類的屬性/方法的基礎上,進一步增添或修改.
引出繼承概念
// 定義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中,只調用子類自己的,或子類繼承的構造函數