Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

8. diel - Polymorfizmus, finálne prvky a autoloader v PHP

V minulej lekcii, Dedičnosť v PHP , sme si vysvetlili dedičnosť a oddědili sme si od človeka javistu. Dnes budeme v PHP tutoriálu v podobnom duchu pokračovať a uvedieme si tzv. Polymorfizmus.

Polymorfizmus

Nenechajte sa vystrašiť príšerným názvom tejto techniky, pretože je v jadre veľmi jednoduchá. Polymorfizmus umožňuje používať jednotné rozhranie pre prácu s rôznymi typmi objektov. Majme napríklad veľa objektov, ktoré reprezentujú nejaké geometrické útvary (kruh, štvorec, trojuholník). Bolo by určite prínosné a prehľadné, keby sme s nimi mohli komunikovať jednotne, hoci sa líšia. Môžeme zaviesť triedu GeometrickyUtvar, ktorá by obsahovala atribút $ farba a metódu vykresli (). Všetky geometrické tvary by potom dedili z tejto triedy jej interface (rozhranie). Objekty kruh a štvorec sa ale iste vykresľujú inak. Polymorfizmus nám umožňuje prepísať si metódu vykresli () pri každej podtriedy tak, aby robila, čo chceme. Rozhranie tak zostane zachované a my nebudeme musieť premýšľať, ako sa to u onoho objekte volá.

Polymorfizmus býva často vysvetľovaný na obrázku so zvieratami, ktoré majú všetky v rozhraní metódu speak (), ale každé si ju vykonáva po svojom.

polymorfizmus - Objektovo orientované programovanie (OOP) v PHP

Podstatou polymorfizmu je teda metóda alebo metódy, ktoré majú všetci potomkovia definované s rovnakou hlavičkou, ale iným telom. Vyskúšajme si to na našich ľuďoch.

Pozdrav

Človek má definovanú metódu pozdrav (), ktorá pozdravia týmto spôsobom:

Ahoj, já jsem Jan

Túto metódu dedí potomkovia človeka, teda aj javista, kde sa zatiaľ metóda chová rovnako. My sme však schopní zdedenú metódu prepísať tak, aby potomok zdravil inak, než človek.

Prepísanie metódy

Prepísanie metódy je veľmi jednoduché, stačí ju v potomkovi len znovu definovať. Naučme teda javisty zdraviť nejakým programátorským spôsobom a pridajme metódu pozdrav () do triedy Javista:

public function pozdrav()
{
    echo('Hello world! Jsem ' . $this->jmeno);
}

Poďme si to vyskúšať do index.php. Aby sme plne pocítili výhody polymorfizmu, urobíme si niekoľko inštancií ľudí a javistů a ty si vložíme do poľa:

$lide = array();
$lide[] = new Clovek('Karel', 'Novák', 30);
$lide[] = new Javista('Jan', 'Nový', 24, 'Eclipse');
$lide[] = new Clovek('Josef', 'Nový', 50);
$lide[] = new Javista('Tomáš', 'Marný', 28, 'NetBeans');
$lide[] = new Clovek('Marie', 'Nová', 32);

Teraz budeme chcieť, aby všetci ľudia pozdravili. Keďže sme použili polymorfizmus, tak na všetkých inštanciách zavoláme pozdrav tým istým spôsobom. Každá inštancia potom pozdravia tak, ako to má naprogramované.

foreach ($lide as $clovek)
{
    $clovek->pozdrav();
    echo('<br />');
}

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;
    }

}
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}...");
    }

    public function pozdrav()
    {
        echo('Hello world! Jsem ' . $this->jmeno);
    }

}

Výstup programu bude nasledujúci:

Tvoja stránka
localhost

Prepísanie metódy nájdeme v anglickej literatúre pod názvom override.

Výhody polymorfizmu

Polymorfizmus je veľmi čistá programátorská technika. Všimnite si, že sme sa vyhli akémukoľvek vetvenia. Nemusíme nikde IFOV či je inštancia človek alebo javista. Predstavte si, že by sme podobných potomkov ľudí mali 100, vetvenia by potom bolo veľmi neprehľadné. Takto je konkrétny logika pre určitý typ človeka vložená v jeho triede, kam logicky patrí. Hromadná práca s inštanciami rôznych typov nebola nikdy jednoduchšia. Využitie samozrejme nájdeme aj pri práci len s jednou inštanciou, kde sa opäť vyhneme vetvenia.

Potomok sa môže rozhodnúť, či si metódu prepíše po svojom alebo si nechá tú zdedenú. Ak budete písať programy objektovo, často sa podobným spôsobom vyhnete inak zložitým konštrukciám, ako je dlhé vetvenia, vnorené cykly a ďalšie.

Kľúčové slovo final

V PHP môžeme použiť kľúčové slovo final, ktoré umožňuje zakázať dedenie tried alebo prepisovanie metód. Hoci je praktický význam tejto techniky diskutabilné, ako vždy ju tu uvádzam pre prípad, že by ste sa s ňou niekedy stretli.

Finálnej metódy

Prepísanie nejaké metódy môžeme v nadtřídě zakázať označením metódy ako finálny. Potomok potom nebude schopný metódu prepísať. Môžeme si to skúsiť v triede Clovek na metóde pozdrav ():

public final function pozdrav()
{
    echo('Ahoj, já jsem ' . $this->jmeno);
}

PHP teraz vyhodí pri spustení skriptu Fatal error, keďže sa potomok Javista snaží prepísať onú finálnej metódu:

Cannot override final method Clovek::pozdrav() in...

Slovo final z definície metódy zas odoberieme.

Finálnej triedy

Ako finálna môžeme označiť aj celú triedu. Zakážeme tým kompletne dedičnosť a táto trieda potom nemôže mať potomkov. Opäť si to skúsme na triede Clovek:

final class Clovek
{

    ...

}

Opäť dostávame Fatal error keďže Javista sa snažia z človeka dediť:

Class Javista may not inherit from final class (Clovek) in...

Význam finálnych prvkov

Ako už bolo spomenuté, význam finálnych prvkov je trochu pochybný. Pôvodnou myšlienkou bolo zakázať dedenia alebo prepisovanie určitých prvkov aplikácie. To môže byť užitočné u veľkých frameworkov s množstvom tried, kde tak násilne zabránime ďalšiemu zesložiťování aplikácie. Prakticky však môže mať neuvážené použitie slova "final" nepríjemné následky, kedy nebude možné využiť výhody dedičnosti a nevyhneme sa písania redundantného kódu. Odporúčal by som slovo final vôbec nepoužívať.

Automatické načítanie tried

Na koniec si ukážme vychytávku, vďaka ktorej nebudeme musieť manuálne requirovat triedy. Je to veľmi užitočné hlavne vo chvíli, keď ich máme veľa a tiež preto, že si nemusíme strážiť, či všetko, čo používame, tiež načítame. To býva niekedy zdrojom nepríjemných chýb.

PHP v starších verziách používalo k automatickému načítanie tried magickú metódu __autoload. Keďže už existuje jej modernejšie alternatíva (funguje od PHP 5.3), ukážeme si rovno tú.

Vo chvíli, keď vytvoríme inštanciu nejakej triedy (alebo k triede pristupujeme staticky, viď. Ďalej v seriáli) PHP skontroluje, či máme takú triedu načítanú. V PHP je možné zaregistrovať funkciu, ktorá sa spustí vo chvíli, keď PHP zistí, že nejakú triedu nepozná. V tejto funkcii nám od PHP príde názov neprevzatých triedy a je na nás, aby sme mu ju načítali pomocou require ().

Prejdime na začiatok index.php a definujme si tu funkciu s ľubovoľným názvom, ktorá berie jeden parameter. Pomocou parametra zostavme cestu k triede a zavolajte require ():

function nactiTridu($trida)
{
    require("tridy/$trida.php");
}

Teraz povieme PHP, že má volať túto funkciu v prípade, keď narazí na použitie neprevzatých triedy:

spl_autoload_register("nactiTridu");

To je celé :) Naša require_once () pre Clovek.php a Javista.php môžeme s kľudom zmazať. Aplikácia bude teraz fungovať rovnako ako predtým a akonáhle použijeme nejakú novú triedu, bude automaticky načítané. Autoloader je potrebné umiestniť v celej aplikácii len raz, niekam na začiatok (kľudne do indexu). O načítanie tried sa už viac nemusíme starať.

Zdrojový kód dnešnej lekcie máte ako vždy k stiahnutiu nižšie a ja sa na vás teším v budúcej lekcii, Riešené úlohy k 7.-8. lekciu OOP v PHP , u statických prvkov.

V nasledujúcom cvičení, Riešené úlohy k 7.-8. lekciu OOP v PHP, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

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é 1058x (2.96 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP

 

Predchádzajúci článok
Dedičnosť v PHP
Všetky články v sekcii
Objektovo orientované programovanie (OOP) v PHP
Preskočiť článok
(neodporúčame)
Riešené úlohy k 7.-8. lekciu OOP v PHP
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity