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í.

6. diel - Referenčnej a primitívne dátové typy v PHP

V minulej lekcii, Kvíz - Úvod, triedy a zapuzdrenie v PHP OOP , sme si vytvorili prvú objektovú komponent, jednalo sa o galériu obrázkov. Začíname pracovať s objektmi a objekty sú referenčnými dátovými typy, ktoré sa v niektorých ohľadoch správajú inak, než tzv. Typy primitívne. Je dôležité, aby sme presne vedeli, čo sa vo vnútri programu deje, inak by nás v budúcnosti mohlo všeličo prekvapiť. Tejto problematike sa budeme v dnešnom PHP tutoriálu venovať.

Primitívne dátové typy

Premenné primitívneho dátového typu sme používali doteraz, ide napr. O číslo alebo o pole. Aj keď primitívne typy v iných jazykoch označujú iba jednoduché štruktúry, ako sú napr. Čísla alebo znaky (od toho názov primitívne), v PHP je primitívnym typom aj polia alebo textový reťazec. Primitívne typy sú vlastne všetky dátové typy okrem objektov.

Kopírovanie hodnoty

Ak niekam odovzdáme primitívne typ, jeho hodnota sa vždy skopíruje. Hoci to určite viete, skúsme si to. Založme si bokom nejaký skript a vytvorme v ňom nové pole s jednou hodnotou 56:

$a = array(56);

Pole $ a teraz pridelené do poľa $ b:

$b = $a;

Do poľa $ b pridajme ešte ďalšie prvok:

$b[] = 28;

Nakoniec Vypíšme obe polia:

print_r($a);
print_r($b);

Keď si teraz zobrazíme zdrojový kód výslednej stránky, výstup bude pravdepodobne tak, ako ste ho očakávali:

Tvoja stránka
localhost

Hoci sme zmenili obsah premennej $ b, jej pôvodná hodnota zostala skopírovaná v premennej $ a. Výsledkom sú teda 2 rôzne polia, prvé len s jednou hodnotou, druhé obsahujúci pôvodnú hodnotu + tú novú.

Referenčnej dátové typy

S referenčnými dátovými typmi, alebo ak chcete s objektmi, je pri odovzdávaní pracované iným spôsobom. Skúsme si vytvoriť podobnú situáciu, ale namiesto čísel ukladajte objekty.

K tomu nám perfektne poslúži inštancie našich ľudí. Vytvorme si analogicky premennú $ as inštancií človeka:

require_once('tridy/Clovek.php');
$a = new Clovek('Karel', 'Novák', 30);

Teraz opäť rozdelia do premennej $ b obsah premennej $ a:

$b = $a;

Opäť po priradení zmeňme hodnotu premennej $ b, tu tak, že užívateľovi v premennej $ b zmeníme vek:

$b->vek = 50;

Opäť vypíšeme obe premenné:

print_r($a);
print_r($b);
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;
    }

}

A hľa, niečo je inak. Mali by ste vidieť takýto výsledok:

Tvoja stránka
localhost

Rekapitulácia

Vytvorili sme si inštanciu človeka a tú sme uložili do premennej $ a. Inštancie a premenná sú však 2 rozdielne veci a to z toho dôvodu, že inštancia nie je priamo uložená v premennej.

Instance objektov sú uložené v pamäti, ktoré sa hovorí halda (anglicky heap). Táto pamäť nie je veľkostne obmedzená (zmestí sa do nej koľko povolíte alebo koľko máte RAM). Túto pamäť si môžeme jednoducho predstaviť ako veľkú haldu objektov. V premennej $ a je potom uložená iba tzv. Referencie, ktorá ukazuje na inštanciu na halde.

Akonáhle sme teda do premennej $ b priradili premennú $ a, povedali sme, že $ b ukazuje na tú istú inštanciu, ako $ a. Celú situáciu som pre vás vizualizoval, aby bola lepšia k pochopeniu:

Halda v PHP - Objektovo orientované programovanie (OOP) v PHP

Na obrázku je znázornená halda s objektmi a premenné, ktoré obsahujú referenciu na tieto objekty. Vidíme, že premenné $ ai $ b ukazujú na ten istý objekt. Z toho dôvodu sa zmenil obsah premennej $ a vo chvíli, keď sme zmenili $ b. Človeka tam máme na rozdiel od predchádzajúcej situácie s poľami iba jedného.

Práca s referenciami je prirodzenejší a mnohokrát aj rýchlejší. Objekt stačí vytvoriť raz a potom ho referencií odovzdávať tam, kde je potreba. Keď chcete v PHP použiť poľa na viacerých miestach, vždy sa jeho obsah kopíruje, čo môže byť pri väčších dátach nevýhodné. Odovzdanie obrovského objektu je úplne nenáročná operácia, pretože sa odovzdáva len referencie. Časom určite uznáte aj to, že je to pre človeka prirodzenejšie a aplikácie sa potom aj lepšie navrhuje. V realite sa nám totiž veci tiež neklonují (väčšinou :) ).

Pozn .: Väčšina programovacích jazykov pracuje Referenčné is poli a textovými reťazcami. Je to hlavne z toho dôvodu, že primitívne typy sú ukladané v pamäti zvanej zásobník (stack). Tá je veľmi rýchla, ale jej veľkosť je tiež veľmi obmedzená. Zložitejšie dátové typy (obyčajne s neobmedzenou dĺžkou) sú vždy ukladané do haldy a vo stacku je umiestnená len referencie na ne. PHP tento fakt pravdepodobne vnútorne obchádza a ako interpreter zachováva správanie primitívnych dátových typov iu polí, aj keď sú fyzicky tiež uložené na halde.

Vynútenie referencie

Ako už bolo povedané, PHP pracuje so všetkým okrem objektov ako s primitívnym typom a to tak, že v prípade odovzdania hodnotu vždy skopíruje. To je niekedy výhodné, ale niekedy zase nevýhodné. Z toho dôvodu existuje možnosť, ako odovzdať premenné primitívneho typu (napr. Pole) referencií. Hneď na úvod by som chcel povedať, aby ste sa použitie týchto hack skôr vyvarovali, pretože mení princíp akým PHP funguje v predvolenom stave a keď na to zabudnete, môže vás to niekedy veľa prekvapiť a spôsobiť veľa nepríjemností. Uvádzam je tu teda skôr pre úplnosť.

Odovzdanie premenné parametrom

Predstavte si, že máte funkciu, po ktorej chcete, aby niečo pridala do poľa, ktoré odovzdáte v jej parametra. Naivné implementácia by mohla vyzerať takto:

// Tento kód nefunguje
function pridej($pole, $prvek)
{
    $pole[] = $prvek;
}

Už pre vás však nebude prekvapením, že tento kód do poľa $ a nič nepridá:

$a = array(1, 2, 3);
pridej($a, 4);
print_r($a);

Je to samozrejme z toho dôvodu, že pole $ a sa skopíruje do premennej $ poľa a do tej sa pridá ďalší prvok. Pôvodný premenná $ a sa však vôbec nezmení. U funkcie môžeme vynútiť referenčnú prístup (ako u objektov) pomocou operátora "&":

function pridej(&$pole, $prvek)
{
    $pole[] = $prvek;
}

Kód bude teraz fungovať, avšak je to skôr taký hack a nie je to príliš pekné. Keby sme napísali kód objektovo (všimnite si, že je to funkcia a nie metóda), tak by sme takéto veci nepotrebovali. Pole by totiž bolo atribútom tohto objektu a nebol by žiadny problém s tým ho modifikovať. Navyše by sme si ušetrili atribút:

public function pridej($prvek)
{
    $this->pole[] = $prvek;
}

Vidíme, ako objekty zjednodušujú situáciu a predchádza neprehľadnému kódu. Neobjektovým riešením by mohlo byť vrátiť modifikované pole pomocou return a potom ho priradiť späť do premennej $ a. Celé pole sa nám tak ale už 2x skopíruje, takže to nie je najvýhodnejšia.

Modifikácie poľa v cykle

Vynútiť referenciu sa nám môže hodiť v prípade, keď prechádzame poľa foreach cyklom a potrebujeme meniť hodnoty. Tento kód nebude fungovať:

// Tento kód nebude fungovat
$a = array(1, 2, 3);
foreach ($a as $prvek)
{
    $prvek++;
}
print_r($a);

Prvok poľa sa skopíruje (ak to nie je objekt) do premennej $ prvok a my meníme až tú, k samotnému prvku sa nedostaneme. S vynútením referencie by to vyzeralo takto:

$a = array(1, 2, 3);
foreach ($a as &$prvek)
{
    $prvek++;
}
print_r($a);

Prvok teraz ukazuje na pôvodnú prvok v poli a mení sa teda pole, nie len skopírovaný prvok. Riešenie je už menej mätúce než u funkcie a párkrát som ho použil, stále však ide obísť cez for cyklus alebo vstavané funkcie, ktoré nám PHP pre prácu s poľami ponúka.

V budúcej lekcii, Riešené úlohy k 4.-6. lekciu OOP v PHP , si uvedieme dedičnosť a polymorfizmus, ktoré patria spolu so skompletovaním k základným pilierom OOP.

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


 

Predchádzajúci článok
Kvíz - Úvod, triedy a zapuzdrenie v PHP OOP
Všetky články v sekcii
Objektovo orientované programovanie (OOP) v PHP
Preskočiť článok
(neodporúčame)
Riešené úlohy k 4.-6. 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