Dziedziczenie

Dziedziczenie służy do tworzenia nowych klas na podstawie innych, rozszerzając ich możliwości. Wykorzystywać będziemy następującej nomenklatury:

Wyobraź sobię klasę jako worek, worek zawierający metody i właściwości, dziedzicząc klasę, przesypujemy właściwości i metody z klasy dziedziczonej.

Do odziedziczonych elementów public i protected, mamy taki sam dostęp jak, w klasie rodzica. Tutaj właśnie objawiają się cechy dostępu protected, elementy takie są dostępne w klasie zawierającej jak i klasach pochodnych.

Elementy private są również dziedziczone, jednak do nich nie uzyskamy bezpośredniego dostępu, pośrednio odwołać możemy się jedynie za pomocą odziedziczonych metod.

PHP obsługuje dziedziczenie proste, oznacza to że dana klasa może dziedziczyć jedynie po jednej klasie. Jednak klasa rodzica także może być pochodną(dziedziczyć) od klasy na wyższym szczeblu. Nazywamy to dziedziczeniem wielopoziomowym.

Przypuśćmy że mamy klasę pradziadek po której dziedziczy klasa dziadek, po niej dziedziczy ojciec a po nim syn. Mówimy że ojciec jest wyżej w hierarhii dziedziczenia, niż syn.

Klasa potomna może dodawać nowe metody i właściwości, jak także przesłaniać te odziedziczone od rodzica. Przesłaniać to znaczy tworzyc metody o takiej samej nazwie jak te w klasie pochodnej.

Dziedziczenie nadajemy za pomocą słowa kluczowego extends



<?php
class Kubek{
    protected $kolor;
    public function ustawKolor($kolor){
        $this->kolor = $kolor;
    }
    public function podajKolor(){
        return $this->kolor;
    }
    private function wyslizgnijSie(){
        echo 'OOPS !';
    }
    public function przedstawSie(){
        return 'Jestem kubek mój kolor '.$this->kolor;
    }
}
class KubekUcho extends Kubek{ //1
    protected $kolorUcha;
     public function ustawKolorUcha($kolor){
        $this->kolorUcha = $kolor;
    }
    public function podajKolorUcha(){
        return $this->kolorUcha;
    }
    public function przedstawSie(){
        //$this->wyslizgnijSie(); //7
        return 'Jestem kubek z uchem moj kolor
         '.$this->kolor.' a ucho '.$this->kolorUcha;
    }

}
class KubekUchoZaroodporny{
// nowe metody i właściwości
}
$zmienna = new KubekUcho; //2
//$zmienna->kolor //3
$zmienna->ustawKolor('czerwony'); //4

echo $zmienna->przedstawSie(); //6

?>

W powyższym kodzie rozszerzamy klase Kubek, tworząc klasę KubekUcho. Nowa klasa dziedziczy właściwości i metody z klasy pochodnej,dodaje swoje właściwości i metody przesłaniając przy tym metodę przedstawSie. Następnie rozszerzamy klasę KubekUchoZaroodporny, klasa ta dziedziczy metody i właściwości od klasy KubekUcho tak więc pośrednio dziedziczy też metody i właściwośći klasy Kubek.

UWAGA - WYWOŁANIE KODU



<?php
class Rodzic{
    private $wartosc;
}
class Dziecko extends Rodzic{

}
$zmienna = new Dziecko;
$zmienna->wartosc = 40;
?>

Nie spowoduje błędu. Zostanie dynamicznie utworzona właściwość $wartosc wewnątrz obiektu wskazywanego przez $zmienna.

Konstruktory, destruktory a dziedziczenie

PHP wykonuje zawsze pierwszy znaleziony konstruktor to znaczy :jeśli w klasie nie ma konstruktora, wywołany zostanie konstruktor klasy rodzica, jeśli rodzic takiego nie posiada wywołany zostanie kostruktor klasy jego rodzica i tak aż do znalezienia konstruktora bądź końca hierarhii klas.

Jeżeli zostanie odnaleziony konstruktor, PHP nie będzie wywoływać konstruktorów położonych wyżej w hierarhii, oznacza to że gdy w klasie znajduje się konstruktor,nie zostanie wywołany konstruktor rodzica.

Nie zachodzi tu nic nowego, poprostu gdy w klasie zdefiniowany zostanie konstruktor, przesłania on wszystkie odziedziczone konstruktory.

Analogicznie ma się sprawa z destruktorami.


<?php
class Dziadek{
protected $nazwisko;
public function podajNazwisko(){
echo 'nazywam sie '.$this->nazwisko;
}
public function __construct($nazwisko){
   $this->nazwisko = $nazwisko;

}}
class Ojciec extends Dziadek{}
class Syn extends Ojciec{}
//$piotr = new Syn;
$piotr = new Syn('Mak');
$piotr->podajNazwisko();

?>

Klasa Syn, dziedziczy konstruktor z klasy Dziadek, tak więc nie możemy stworzyc obiektu nie podając argumentu.

Modyfikator dostępu

Przesłonięte metody możemy wywoływać za pomocą modyfikatora parent:: . Dzięki temu możemy np wywołać konstruktor, destruktor rodziców.

Przykład z kubkami z wykorzystaniem nowych wiadomości.



<?php
class Kubek{
    private $kolor;
    public function __construct($kolor){
         $this->kolor = $kolor;
    }
    public function  __destruct() {
        echo 'zniszczony kubek';
    }
    public function przedstawSie(){
        return 'Jestem kubek moj kolor '.$this->kolor;
    }
}
class KubekUcho extends Kubek{ 
    protected $kolorUcha;
    public function  __construct($kolor,$kolorUcha) {
        parent::__construct($kolor);//1
        $this->kolorUcha = $kolorUcha;
    }
    public function podajKolorUcha(){
        return $this->kolorUcha;
    }
    public function przedstawSie(){
        return parent::przedstawSie(). //2
               ' a ucho '.$this->kolorUcha;
    }

}

?>

Modyfikator final

Modyfikator ten oznacza że w klasie znajduje się końcowa wersja funkcji, oznacza to że w funkcjach pochodnych nie wolno przesłaniać danej funkcji.

Gdy użyjemy modyfikatora final w stosunku do klasy, oznacza to że dana klasa nie może być dziedziczona.