IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

9. diel - Statika v PHP

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

V minulej lekcii, Riešené úlohy k 7.-8. lekciu OOP v PHP , sme si vysvetlili ako funguje polymorfizmus a naučili sa používať autoloader pre automatické načítanie tried. V dnešnom PHP tutoriálu sa zoznámime s veľmi kontroverzné technikou - statikou.

Pozor na statiku - Objektovo orientované programovanie (OOP) v PHP
POZOR! Dnešné lekcie vám ukáže statiku, teda postupy, ktoré v podstate narušujú objektový model. OOP je obsahuje len pre špeciálne prípady a všeobecne platí, že všetko ide napísať bez statiky. Vždy musíme starostlivo zvážiť, či statiku naozaj nutne potrebujeme. Všeobecne by som odporúčal statiku vôbec nepoužívať, ak si nie ste úplne istí, čo robíte. Podobne, ako globálne premenné je statika v objektovom programovaní niečo, čo umožňuje písať zlý kód a porušovať dobré praktiky. Znalosti použite s rozvahou, na svete bude potom menej zla.

Triedny prvky

V objektovo orientovanom programovaní sme už trochu zbehli a preto vieme, že aplikácia je zložená z množiny komunikujúcich objektov. Objekty sú vždy inštancie, vytvorené podľa nejakej triedy. Každá inštancia je unikátny a má svoj vnútorný stav (atribúty) a schopnosti (metódy).

Objektovo orientované programovanie však okrem inštančných prvkov umožňuje definovať aj prvky triedny. Jedná sa o atribúty a metódy, ktoré nepatria inštanciu, ale patrí triede. Triedny metódu teda voláme na triede, miesto na inštanciu a inštanciu vôbec nepotrebujeme. Takúto metódu označíme kľúčovým slovom static a môžeme ju zavolať odkiaľkoľvek z programu bez toho aby sme mali inštanciu. Skúsme si to na jednoduchom príklade.

Matematická trieda

Vytvorme si v zložke "tridy" novú triedu Matematika.php. Do nej najprv umiestnime inštančný metódu na druhú (), ako sme boli zvyknutí doteraz:

class Matematika
{

    public function naDruhou($zaklad)
    {
        return $zaklad *$zaklad;
    }

}

V index.php si skúsme nechať vypočítať druhú mocninu pomocou našej metódy. Vytvoríme si inštanciu našej triedy Matematika a zavoláme na nej príslušnú metódu:

require_once('tridy/Matematika.php');

$matematika = new Matematika();
echo($matematika->naDruhou(12));
class Matematika
{

    public function naDruhou($zaklad)
    {
        return $zaklad *$zaklad;
    }

}

Výstupom programu je samozrejme číslo 144, ale o ten tu teraz nejde. Predstavte si, že v nejakej výpočtovej aplikácii používate na mnohých miestach v mnohých triedach nejaké podobné pomocné výpočty. Bolo by trochu nepraktické stále tvoriť nové inštancie alebo si odovzdávať inštanciu triedy Matematika. Z toho dôvodu urobíme metódu na druhú () statickú. Upravme triedu Matematika na túto podobu:

class Matematika
{

    public static function naDruhou($zaklad)
    {
        return $zaklad *$zaklad;
    }

}

V index.php odstránime vytvorenie inštancie a metódu na druhú () budeme volať priamo na triede Matematika. K volanie triednych prvkov nepoužívame operátor šípky (->), ale čtyřtečku (: :):

require_once('tridy/Matematika.php');

echo(Matematika::naDruhou(12));
class Matematika
{

    public static function naDruhou($zaklad)
    {
        return $zaklad *$zaklad;
    }

}

Metódu sme zavolali bez inštancie. Dá sa povedať, že je tiež globálna a viditeľná odkiaľkoľvek, čo môže pri zlom použití spôsobiť veľmi zlú čitateľnosť kódu (viď ďalej). Vieme, že OOP sa snažia skôr čo najviac vecí skrývať. V tomto prípade je to však v poriadku a ďalej v seriáli si vysvetlíme ďalšie správna i zlá použitie.

Kombinácia statických a inštančných prvkov

Trieda nemusí obsahovať len inštančný alebo len statické prvky, ale môže obsahovať ich kombináciu. Inštančný prvky sú potom prístupné len na inštanciu, statické zase len na triede.

Číslovanie inštancií

O statických prvkoch môžeme zjednodušene povedať, že sú spoločné pre všetky inštancie, pretože patrí tej jednej triede. Vráťme sa zas k našim ľuďom a dajme tomu, že ich budeme potrebovať číslovať. Každý človek bude mať atribút $ id, v ktorom bude unikátne číslo. Prvý vytvorený človek bude mať $ id = 1, druhý $ id = 2 a tak ďalej. Kde ale uchovávať koľko ľudí sme už vytvorili?

Ak poznáme statiku, nie je nič jednoduchšie ako pridať do triedy Clovek statický atribút pocetLidi, nastavený na 0. Trieda si teda pamätá koľko ľudí bolo vytvorené. Je to aj logicky správne, pretože atribút je zdieľaný medzi všetkými inštanciami a preto je na triede. V konstruktoru človeka potom tento statický atribút vždy zvýšime o 1 a do inštančný premennej $ id dosadíme toto číslo.

Trieda Clovek.php bude vyzerať s touto malou úpravou nasledovne:

class Clovek
{

    public $jmeno;
    public $prijmeni;
    public $vek;
    private $unava = 0;
    public $id;
    private static $pocetLidi = 0;

    public function __construct($jmeno, $prijmeni, $vek)
    {
        $this->jmeno = $jmeno;
        $this->prijmeni = $prijmeni;
        $this->vek = $vek;
        self::$pocetLidi++;
        $this->id = self::$pocetLidi;
    }

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

    protected function celeJmeno()
    {
        return $this->jmeno . ' ' . $this->prijmeni;
    }

    public function __toString()
    {
        return $this->jmeno . ' - ' . $this->id;
    }

}

Pri bližšom pohľade vidíme 2 nové atribúty, inštančný $ id a triedny $ pocetLidi.

V konstruktoru inkrementuje (zvýšime o 1) premennú $ pocetLidi a hodnotu dosadíme nové inštanciu do jej $ id. Ku statickým prvkom sa vnútri triedy pristupuje pomocou kľúčového slova self. Má podobný význam ako $ this, ktoré uchovávalo aktuálne inštanciu, self uchováva aktuálne triedu. Mätúce môže byť, že sa za čtyřtečku na rozdiel od $ this píše dolár.

Posledná zmena spočíva v metóde __toString (), kde vraciame aj ID, aby sme jednoducho videli, že nám ich prideľovanie funguje.

V index.php poupravíme cyklus tak, aby namiesto zdravenie ľudí vypisoval. Pre úplnosť dodávam aj ich tvorenia:

require_once('tridy/Clovek.php');
require_once('tridy/Javista.php');

$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);

foreach ($lide as $clovek)
{
    echo($clovek . '<br />');
}
class Clovek
{

    public $jmeno;
    public $prijmeni;
    public $vek;
    private $unava = 0;
    public $id;
    private static $pocetLidi = 0;

    public function __construct($jmeno, $prijmeni, $vek)
    {
        $this->jmeno = $jmeno;
        $this->prijmeni = $prijmeni;
        $this->vek = $vek;
        self::$pocetLidi++;
        $this->id = self::$pocetLidi;
    }

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

    protected function celeJmeno()
    {
        return $this->jmeno . ' ' . $this->prijmeni;
    }

    public function __toString()
    {
        return $this->jmeno . ' - ' . $this->id;
    }

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

Tvoja stránka
localhost

Vidíme, že statický atribút $ pocetLidi naozaj náleží triede Clovek. Keď PHP triedu prvýkrát načíta, vytvorí atribút a nastaví do neho hodnotu 0. Statický atribút na triede Clovek v pamäti pretrváva do skončenia skriptu bez ohľadu na to, či existujú nejaké inštancie ľudí alebo nie. S jeho hodnotou môžeme manipulovať z inštančných metód (tu z konstruktoru). Zo statickej metódy nemožno volať metóda inštančný, pretože k tomu potrebujeme inštancii :) Naopak to teda nedá.

Bez statiky by sa tento príklad riešil pomocou objektu, ktorý by ľudí vyrábal. Takým objektom sa hovorí továrne, ale o tom zas niekedy inokedy.

Statika je veľmi dôležitá, veľmi používaná a často veľmi mylne chápaná programátorská technika. Z toho dôvodu ju budú venované ešte 2 nasledujúce lekcie. Povieme si kedy ju používať a kedy nie. Budete na ňu narážať často a je veľmi dôležité, aby ste chápali ako funguje. V budúcej lekcii, Triedny prvky v PHP druhýkrát - konštanty , budeme pokračovať a vysvetlíme si ako sa v PHP používajú konštanty. Súbory z dnešnej lekcie sú ako vždy k stiahnutiu v archíve nižšie.


 

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

 

Predchádzajúci článok
Riešené úlohy k 7.-8. lekciu OOP v PHP
Všetky články v sekcii
Objektovo orientované programovanie (OOP) v PHP
Preskočiť článok
(neodporúčame)
Triedny prvky v PHP druhýkrát - konštanty
Č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