7. diel - Dedičnosť v PHP
V predchádzajúcom cvičení, Riešené úlohy k 4.-6. lekciu OOP v PHP, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Riešené úlohy k 4.-6. lekciu OOP v PHP , sme si vysvetlili rozdiel medzi referenčnými a primitívnymi dátovými typy. Dnes si v PHP tutoriálu opäť rozšírime znalosti o objektovo orientovanom programovaní. V úvodnom dieli do OOP sme si hovorili, že OOP stojí na troch základných pilieroch: zapuzdrenie, dedičnosti a polymorfizmu. Zapuzdrenie a používanie modifikátora private nám je už dobre známe. Dnes sa pozrieme na dedičnosť.
Dedičnosť
Dedičnosť je jedna zo základných techník OOP a slúži k tvoreniu nových dátových štruktúr na základe starých. Vyskúšame si to opäť na našom príklade s ľuďmi.
Ak si dobre spomínate, všetci naši ľudia vedia pozdraviť, spať a behať. My budeme ale chcieť do našej aplikácie pridať Javistu (pardon, ale PHPista znie divne ) Keď mi napíšete ako sa programátorom v tomto jazyku hovorí, zmením to.), Ktorý bude vedieť to isté, ako človek, ale navyše bude vedieť aj programovať.
Pridajte si do zložky tridy novú triedu Javista.php. Mohli by sme samozrejme skopírovať triedu človek a len do nej pridať metódu programujte (). Kód by vyzeral asi takto:
<?php class Javista { public $jmeno; public $prijmeni; public $vek; private $unava = 0; public function __construct($jmeno, $prijmeni, $vek) { $this->jmeno = $jmeno; $this->prijmeni = $prijmeni; $this->vek = $vek; } public function spi($doba) { $this->unava -= $doba * 10; if ($this->unava < 0) $this->unava = 0; } public function behej($vzdalenost) { if ($this->unava + $vzdalenost <= 20) $this->unava += $vzdalenost; else echo('Jsem příliš unavený.'); } public function pozdrav() { echo('Ahoj, já jsem ' . $this->jmeno); } public function programuj() { echo('Programuji...'); } public function __toString() { return $this->jmeno; } }
Kód je veľmi redundantné a keď budeme chcieť niečo zmeniť v človeku, musíme to zmeniť aj tu a v ďalších podobných triedach. Asi uznáte, že toto nie je vhodný spôsob ako aplikáciu rozširovať.
Upravme teraz triedu tak, aby používala dedičnosť:
<?php class Javista extends Clovek { public function programuj() { echo('Programuji...'); } }
PHP teraz triedu Javista oddědí od triedy Clovek. Toho sme docielili pomocou kľúčového slova Extends. To znamená, že programátor bude obsahovať všetky metódy a všetky atribúty, ktoré má trieda Clovek plus navyše to, čo pridáme do jeho triedy.
Navyše vidíme v triede metódu programujte (). Modifikujte kód v index.php tak, aby bol v premennej $ jan javista a nechajme ho pozdraviť a programovať:
{PHP} require_once('tridy/Clovek.php'); require_once('tridy/Javista.php'); $karel = new Clovek('Karel', 'Novák', 30); $jan = new Javista('Jan', 'Nový', 24); $karel->behej(10); $karel->behej(10); $karel->spi(1); $karel->behej(10); $jan->pozdrav(); echo('<br />'); $jan->programuj();
{PHP} class Clovek { public $jmeno; public $prijmeni; public $vek; private $unava = 0; public function __construct($jmeno, $prijmeni, $vek) { $this->jmeno = $jmeno; $this->prijmeni = $prijmeni; $this->vek = $vek; } public function spi($doba) { $this->unava -= $doba * 10; if ($this->unava < 0) $this->unava = 0; } public function behej($vzdalenost) { if ($this->unava + $vzdalenost <= 20) $this->unava += $vzdalenost; else echo('Jsem příliš unavený.'); } public function pozdrav() { echo('Ahoj, já jsem ' . $this->jmeno); } public function __toString() { return $this->jmeno; } }
{PHP} class Javista extends Clovek { public function programuj() { echo('Programuji...'); } }
Z výstupu programu vidíme, že všetko funguje ako má. Jan má ako atribúty a metódy človeka, tak Javisty:
Dedičnosť nájdete v anglickej literatúre pod pojmom inheritance.
Výhody dedičnosti
Výhody dedenie sú jasné, nemusíme opisovať obom triedam tie isté atribúty, ale stačí dopísať len to, v čom sa líšia. Zvyšok sa zdedí. Prínos je obrovský, môžeme rozširovať existujúce komponenty o nové metódy a tým je znovu využívať. Nemusíme písať hŕbu redundantného (duplikovaného) kódu. A hlavne - keď zmeníme jediný atribút v materskej triede, automaticky sa táto zmena všade zdedí. Nedôjde teda k tomu, že by sme to museli meniť ručne u 20tich tried a niekde na to zabudli a spôsobili chybu. Sme ľudia a chybovať budeme vždy, musíme teda používať také programátorské postupy, aby sme mali možnosť chybovať čo najmenej.
O materskej triede sa niekedy hovorí ako o predkovi (tu Clovek) ao triede, ktorá z nej dedí, ako o potomkovi (tu Javista). Potomok môže pridávať nové metódy alebo si prispôsobovať metódy z materskej triedy (viď ďalej). Môžete sa stretnúť aj s pojmami nadtřída a podtrieda.
V objektovom modelovania sa dedičnosť znázorňuje graficky ako prázdna šípka smerujúca k predkovi.
Jazyky, ktoré dedičnosť podporujú, buď vie dedičnosť jednoduchú, kde trieda dedí len z jednej triedy, alebo viacnásobnú, kde trieda dedí hneď z niekoľkých tried naraz. Viacnásobná dedičnosť sa v praxi príliš neosvedčila, časom si povieme prečo a ukážeme si aj ako ju obísť. PHP podporuje iba jednoduchú dedičnosť, s viacnásobnou dedičnosťou sa môžete stretnúť napr. V C ++. Potomok samozrejme môže mať ďalšieho potomka a tak ďalej.
Dedičnosť a konštruktory
Pridajme nášmu Javistovi navyše nejaký atribút. Bude sa jednať napr. O IDE (editor zdrojových kódov), ktoré k programovanie používa.
Pridajme triede Javista verejný atribút $ ide:
public $ide;
A metódu Programujte () upraví tak, aby vypisovala aj v čom javista programuje:
public function programuj() { echo("Programuji v {$this->ide}..."); }
Volanie konstruktoru predka
Samozrejme sa nám bude hodiť nastaviť atribút $ ide v konstruktoru javisty. PHP nám konštruktor zdedilo z predka. Ak potrebujeme iný, musíme si ho znovu definovať.
Definujme si teda svoj vlastný. Mal by obsahovať všetko čo je potrebné k vytvoreniu predka + naše nové atribúty. Aby sme nemuseli nastavovať všetky atribúty ako sme to robili v predkovi, jednoducho nastavíme len atribúty javisty a na zvyšok zavoláme konštruktor predka. To urobíme pomocou premennej parent. Operátoru čtyřtečky sa neľakajte, vysvetlíme si ho podrobnejšie ďalej v seriáli.
public function __construct($jmeno, $prijmeni, $vek, $ide) { $this->ide = $ide; parent::__construct($jmeno, $prijmeni, $vek); }
Nakoniec upravíme index.php:
{PHP} require_once('tridy/Clovek.php'); require_once('tridy/Javista.php'); $karel = new Clovek('Karel', 'Novák', 30); $jan = new Javista('Jan', 'Nový', 24, 'Eclipse'); $karel->behej(10); $karel->behej(10); $karel->spi(1); $karel->behej(10); $jan->pozdrav(); echo('<br />'); $jan->programuj();
{PHP} class Clovek { public $jmeno; public $prijmeni; public $vek; private $unava = 0; public function __construct($jmeno, $prijmeni, $vek) { $this->jmeno = $jmeno; $this->prijmeni = $prijmeni; $this->vek = $vek; } public function spi($doba) { $this->unava -= $doba * 10; if ($this->unava < 0) $this->unava = 0; } public function behej($vzdalenost) { if ($this->unava + $vzdalenost <= 20) $this->unava += $vzdalenost; else echo('Jsem příliš unavený.'); } public function pozdrav() { echo('Ahoj, já jsem ' . $this->jmeno); } public function __toString() { return $this->jmeno; } }
{PHP} class Javista extends Clovek { public $ide; public function __construct($jmeno, $prijmeni, $vek, $ide) { $this->ide = $ide; parent::__construct($jmeno, $prijmeni, $vek); } public function programuj() { echo("Programuji v {$this->ide}..."); } }
A vyskúšame:
Modifikátor protected
V príklade vyššie nebudú v potomkovi prístupné privátnej atribúty, ale iba atribúty a metódy s modifikátorom public. Private atribúty a metódy sú chápané ako špeciálne logika konkrétnej triedy, ktorá je potomkovi utajená, aj keď ju vlastne používa, nemôže ju meniť. Môžete si vyskúšať, že hoci javista vie spať, nie sme schopní vo vnútri jeho triedy nijako zasahovať do atribútu $ unava. V tomto prípade je to tak správne, pretože všetci ľudia budú spať rovnakým zůsobem a nie je dôvod, aby do tohto spôsobu potomkovia ľudí zasahovali.
Ak by sme chceli nejaký atribút (alebo metódu) neprístupný zvonku, ale zároveň prístupný v potomkoch, použijeme modifikátor prístupu protected. Vytvorme si pomocnú metódu v triede Clovek, ktorá nám vráti jeho celé meno (teda $ jmeno + $ priezvisko). Metódu budeme chcieť používať len na interné účely triedy a všetkých tried, ktoré z nej dedia. Označíme ju teda ako protected:
protected function celeJmeno() { return $this->jmeno . ' ' . $this->prijmeni; }
Metódu teraz nebudeme schopní zavolať v index.php (mimo triedu), ale budeme ju schopní zavolať ako v triede Clovek, tak v triede Javista. Pokračovať budeme zas v budúcej lekcii, Polymorfizmus, finálne prvky a autoloader v PHP , kedy si uvedieme polymorfizmus.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 825x (2.79 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP