Programowanie obiektowe > Lekcja 6
Dziedziczenie
Ostatnia modyfikacja: 01.06.2021
Przed Tobą wielka rzecz w programowaniu obiektowym: dziedziczenie. Pewnie rozumiesz samo pojęcie dziedziczenia poza programowaniem (na przykład dziecko dziedziczy kolor oczu po matce). W programowaniu mamy podobnie: tworzona klasa może dziedziczyć po innej klasie, to znaczy przejąć jej właściwości oraz metody. Rzecz jasna klasa, która dziedziczy, również może mieć swoje metody czy właściwości.
A więc pozostając przy tematyce ludzi, spójrzmy na jakiś przykład. Wyobraź sobie, że mamy system obsługujący przychodnię lekarską i dzieci oraz osoby dorosłe muszą być inaczej potraktowane. Jest jednak sporo informacji, jakie należy zebrać na temat każdej osoby: imię i nazwisko, adres, PESEL i podobne. Zapiszmy to przy użyciu klasy bazowej i dwóch klas dziedziczących.
<?php
class Person
{
public string $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
class Adult extends Person
{
// code for adults
}
class Child extends Person
{
public function checkVaccinations(): bool
{
// code...
return true;
}
}
$person = new Child('Jan Kowalski');
echo $person->getName(); // result: Jan Kowalski
var_dump($person->checkVaccinations()); // result: bool(true)
Klasę, po której chcemy dziedziczyć, określamy poprzez extends
. Gdybyśmy dziedziczenia nie znali, to musielibyśmy skopiować część funkcji z jednej klasy do drugiej, co rodziłoby tylko problemy. Zawsze trzeba byłoby szukać, sprawdzać i zmieniać to samo w wielu miejscach
Ciekawostka
Co ciekawe, wspomniany w początkowej lekcji OOP, instanceof
sprawdza także klasy, po których dziedziczy dana instancja. Czyli, idąc za powyższym przykładem, $person instanceof Person
zwróci prawdę, pomimo że to obiekt klasy Child
. Podobnie działa określenie typu argumentu. Wystarczy, że klasa będzie rozszerzała (lub implementowała, ale o tym kawałek dalej) wskazaną klasę i typ będzie zgodny. To całkiem pomocne, bo możemy dopuścić inne klasy, które łączy pożądana przez nas rzecz.
Nadpisywanie elementów
Ktoś pewnie zastanowi się teraz co stanie się, gdy utworzy w klasie metodę lub właściwość o takiej samej nazwie, jaka już istnieje w klasie, po której dziedziczy. Śpieszę z wyjaśnieniem, że element z klasy bazowej zostanie nadpisany. Innymi słowy, właściwość będzie miała taką wartość lub jak w klasie, która dziedziczy, a metoda będzie robiła to, co ta zapisana w klasie, która dziedziczy. Może trochę zawile to brzmi, ale chyba rozumiesz działanie. Jeśli nie to poniższy przykład na pewno wszystko rozjaśni:
<?php
class Person
{
public string $name = 'Jan';
}
class Child extends Person
{
public string $name = 'Marek';
}
$person = new Child();
echo $person->name; // result: Marek
Jeżeli jednak zaistnieje potrzeba wywołania nadpisanej metody z klasy bazowej, to jest taka możliwość. Wystarczy wywołać metodę z dopiskiem parent::
.
<?php
class Person
{
public function checkVaccinations()
{
// code...
echo 'Check person!';
}
}
class Child extends Person
{
public function checkVaccinations()
{
parent::checkVaccinations();
echo 'Check child!';
}
}
$person = new Child();
$person->checkVaccinations(); // result: Check person!Check child!
Modyfikator protected
W tym miejscu muszę jeszcze na chwilkę wrócić do modyfikatorów dostępu. Wspominałem tam o protected
i dziedziczeniu. Sprawa wygląda tak, że właściwość czy metoda oznaczona w ten sposób będzie widoczna w klasie bazowej, ale też w klasach ją rozszerzających. Jednak tylko wewnątrz, z zewnątrz dostęp daje wyłącznie public
. Z private
widoczność jest ograniczana tylko do klasy deklaracji. Przykładowo:
<?php
class Person
{
private string $name;
public function __construct(string $name)
{
$this->name = $name;
}
protected function getName(): string
{
return $this->name;
}
}
class Child extends Person
{
public function showName()
{
echo $this->getName(); // result: Andrzej
echo $this->name; // result: warning, undefined property
}
}
$person = new Child('Andrzej');
echo $person->showName();
echo $person->getName(); // result: fatal error
Mam nadzieję, że udało Ci się zrozumieć dziedziczenie, choć dopiero w praktyce poznasz, jakie daje to możliwości. To bardzo przydatna sprawa, idealna do wykorzystania w naprawdę wielu miejscach. Momentami problematyczne może wydawać się to, że nie widzisz w jednym miejscu, jakie metody ma dana klasa. Dlatego właśnie warto programować w IDE, które wszystko analizuje i podpowiada :)
Komentarze