Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij slevové akce 50% výuky zdarma!
Pouze tento týden sleva až 80 % na e-learning týkající se Javy

Lekce 4 - Zapouzdření v PHP

V předešlém cvičení, Řešené úlohy k 1.-3. lekci OOP v PHP, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes si v tutoriálu povíme něco o zapouzdření v PHP.

Zapouzdření

OOP stojí na třech základních pilířích: Zapouzdření, Dědičnosti a Polymorfismu. První z nich si dnes probereme.

Zapouzdření umožňuje skrýt některé metody a atributy tak, aby zůstaly použitelné jen pro třídu zevnitř. Objekt si můžeme představit jako černou skřínku (anglicky blackbox), která má určité rozhraní (interface), přes které jí předáváme instrukce/data a ona je zpracovává.

Nevíme, jak to uvnitř funguje, ale víme, jak se navenek chová a používá. Nemůžeme tedy způsobit nějakou chybu, protože využíváme a vidíme jen to, co tvůrce třídy zpřístupnil.

U naší třídy člověk by mohl být problém ve chvíli, když by měla mít atribut $datumNarozeni a na jeho základě další atributy: $plnolety a $vek. Kdyby někdo objektu zvenčí změnil $datumNarozeni, přestaly by platit proměnné plnolety a vek. Říkáme, že vnitřní stav objektu by byl nekonzistentní. Toto se nám ve strukturovaném programování může klidně stát. V OOP však objekt zapouzdříme a atribut $datumNarozeni označíme jako privátní, zvenčí tedy nebude viditelný. Naopak ven vystavíme metodu zmenDatumNaro­zeni(), která dosadí nové datum narození do proměnné datumNarozeni a zároveň provede potřebný přepočet věku a přehodnocení plnoletosti. Použití objektu je bezpečné a aplikace stabilní.

Zapouzdření tedy donutí programátory používat objekt jen tím správným způsobem. Rozhraní (interface) třídy rozdělí na veřejně přístupné (public) a vnitřní strukturu (private).

Obecně bývá snaha skrýt toho v objektu co nejvíce a zvenčí zpřístupnit jen to důležité. Do data narození se u našich lidí pouštět nebudeme, jelikož výpočet věku není úplně triviální.

Spánek

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Privátní atributy slouží tedy objektům ke zpracovávání nějaké jejich vnitřní logiky, která zvenčí není vidět a nemůžeme do ní zasahovat. Do funkce lidí jistě spadá spánek a poslouží tedy jako dokonalý ukázkový příklad.

Člověk bude mít nějakou únavu, která bude uložená v privátním atributu $unava.

Dále bude mít metodu spi(), která bude brát v parametru počet hodin, které má člověk naspat. Metoda spi() sníží únavu podle toho, kolik hodin člověk naspí. Samozřejmě nezapomeneme ošetřit, aby nebyla únava záporná když se někdo pokusí naspat více hodin, než je možné.

Aby bylo možné člověka i unavit, dáme mu metodu behej(), která bude v parametru brát počet kilometrů. Pro jednoduchost si metodu naprogramujme tak, aby za každý kilometr přičetla 1 jednotku únavy. Pokud je únava příliš vysoká, metoda vypíše, že již běhat nelze.

Třída Clovek s novou funkcionalitou bude vypadat asi takto:

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

}

Všimněte si, že jsme atributu únava při jeho deklaraci rovnou nastavili hodnotu 0. Tato hodnota se nastaví každé instanci při jejím vytvoření a je to tedy alternativa k tomu, kdybychom přiřazení nuly napsali do konstruktoru.

Jinak na třídě není kromě privátního modifikátoru přístupu u atributu $unava nic, co bychom již neviděli. Metoda behej() není příliš elegantní, jelikož v případě velké únavy (vyšší než 20 jednotek) přímo vypisuje hlášku, že je člověk příliš unavený. To snižuje univerzálnost objektu, jelikož takový výpis nemusíme vždy chtít. Pro naše účely je to však nyní ideální a během seriálu si ukážeme jak se chybové stavy objektů správně řeší.

Zvenku objektu není možné měnit únavu jinak, než unavením člověka pomocí metody behej() nebo necháním člověka vyspat. Tedy tak, jak jsme to my, autoři třídy, navrhli. Objekt nelze rozbít nebo použít špatně.

Přesuňme se do index.php a novou funkcionalitu si otestujme. Můžeme vymazat volání zdravení na obou našich instancích a jednu z nich nechme uběhnout 3x 10km:

$karel->behej(10);
$karel->behej(10);
$karel->behej(10);
// Obsah souboru Clovek.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;
    }
}

Výstup programu je:

Your page
localhost

Karel uběhl 2x 10km a poté dosáhl stanovené hranice únavy, kterou jsme zvolili na 20 jednotek. Další pokus o běh se tedy již nezdařil a program jednou vypsal, že je příliš unavený.

Dodejme do programu spánek, na 10km vzdálenosti jsme v kódu zvolili 1 hodinu spánku. Dodejme tedy tuto hodinu před posledních 10km:

$karel->behej(10);
$karel->behej(10);
$karel->spi(1);
$karel->behej(10);
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;
    }

}

Chybová hláška nyní zmizela a vše proběhlo v pořádku.

Když se pokusíme zvenčí (z kteréhokoli jiného souboru, než je Clovek.php) přistoupit k privátnímu atributu $unava, dostaneme vyhubováno:

$karel->unava = 0;

Your page
localhost

Privátní metody

Privátní mohou být samozřejmě nejen atributy, ale i metody, které vykonávají nějakou funkcionalitu pro vnitřní potřebu třídy. Často se používají také v případě, když máme příliš složitou veřejnou metodu. V tu chvíli ji rozdělíme na několik privátních metod, které veřejná metoda volá. Počet řádků v metodě by ideálně neměl přesáhnout asi 30, počet řádků na třídu asi 500. Nyní je to jedno, u větších projektů a tříd je dobré se tím řídit a v případě velkého rozsahu jednoduše funkcionalitu rozdělit do více komponent, které spolu budou spolupracovat. Jen tak dokážeme udržet naši aplikaci čitelnou a dále rozšiřitelnou.

Aplikaci máte jako vždy níže ke stažení.

V příští lekci, První objektová komponenta v PHP - Galerie obrázků, si vytvoříme první komponentu, která bude mít reálné použití. Půjde o galerii obrázků.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 687x (877 B)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Řešené úlohy k 1.-3. lekci OOP v PHP
Všechny články v sekci
Objektově orientované programování (OOP) v PHP
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
41 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (15)

 

 

Komentáře
Zobrazit starší komentáře (37)

Avatar
Martin Konečný (pavelco1998):10.10.2015 21:16

Jen v metodě běhej se ti může trochu rozházet energie. I přes to, že je člověk unavený, pořád se mu sníží energie, takže pak může být i v minusu :)

Odpovědět
10.10.2015 21:16
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Vít Cigánek:11.10.2015 10:24

Já tomu rozumím. Ale pro ilustraci mi to stačí. Když v podstatě jdou kilometry do mínusu tak říká že je unavený. Prostě přepočítává energii jestli to uběhne nebo ne.

 
Odpovědět
11.10.2015 10:24
Avatar
Petr Škopek
Člen
Avatar
Petr Škopek:19.8.2017 17:48

Mohu se zeptat, proč nikde není definována proměnná $doba? Mohu tuto proměnnou ve třídě použít, pokud ji nemám nikde ve třídě definovanou?

 
Odpovědět
19.8.2017 17:48
Avatar
Odpovídá na Petr Škopek
Martin Konečný (pavelco1998):19.8.2017 18:01

Tu proměnnou $doba dostane metoda spi() parametrem.
Takže třeba

$clovek->spi(20);

Pak v proměnné $doba bude číslo 20

Odpovědět
19.8.2017 18:01
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Ondřej Vaňkát:25.5.2020 7:58

Má private, protected, public nějaký vliv na napadeni aplikace z venku ? Například mi někdo nabourá aplikaci, protože jsem nějakou metodu/atribut dal public.
Díky

 
Odpovědět
25.5.2020 7:58
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Pavel Kubalík:11. ledna 15:06

Dobrý den
Jelikož, je tato lekce trochu jednodušší vrátil jsem se k vzorovému řešení minulého třetího (pokročilejšího) příkladu. Měl jsem z toho komplex méněcennosti. Bude úspěch když někdy řešení zcela pochopím (v hrubých rysech to chápu). Fakt je, že to vymýšlí špičkoví programátoři ČR a to já zdaleka nejsem a ani už nebudu.
Rovněž jsem se podíval na další příklady a nejsem si jist jak je zvládnu. Rozhodně musím velmi a velmi zpomalit a hodně přemýšlet. Nevím, nevím zda to zvládnu.
Trochu jsem se rozveselil, když jsem si vzpomněl na ukončení základního kurzu PHP. Když jsem dokončil svůj první kurz (SQLite) přišel mi email. Nyní nic (asi se to normálně nenosí). Těšil jsem se na certifikát, který byl slibován, když vyřeším všechny povinné (!) příklady, ale nic. Já k ničemu žádný papír nepotřebuji, ale jak to vysvětlit mým dětem a vnoučatům (pravnučky zatím mají jiné starosti). Snažím se však myslet pozitivně. Každopádně moje důvěra způsobila, že jsem se všem těmto příkladům věnoval, a něco se naučil. Že je to ztráta důvěry. A co? To je dnes normální. Účel světí prostředky. Takže hlavu vzhůru, zpomalit, zatnout zuby a pokračovat.
Děkuji PK

 
Odpovědět
11. ledna 15:06
Avatar
t.teichmanova:22. dubna 19:55
Opět jsem si s Vašim programem trochu pohrála a zkusila jej trochu modifikovat.
<?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 behej($vzdalenost)
    {
        if ($this->unava + $vzdalenost >= 20){
                 echo('Jsem příliš unavený.<br>');
                }else{
                  echo "Jsem v pohodě.<br><br>";
          }
}
    public function pozdrav()
    {
        echo('Ahoj, já jsem ' . $this->jmeno . "<br>");
    }

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

}

$karel = new Clovek('Karel', 'Novák', 10);
$jan = new Clovek('Jan', 'Nový', 24);

$karel->pozdrav();
$karel->behej(5);

$jan->pozdrav();
$jan->behej(30);


?>

   Zdravím a přeju krásné dny

                                                               T.T.
 
Odpovědět
22. dubna 19:55
Avatar
t.teichmanova:29. dubna 21:19
 Ještě jednou jsem se pročítala touto lekci, kde se uvádí rozhraní-interface. V programu ale neni nebo jsem ho tam možná nenašla, tak jsem jej tam přidala. Snad jsem neporušila autorská práva při úpravě Vašeho programu.
  Zde je moje trochu upravená verze :

<?php
interface Demo {
 public function technologie();
 }

class Clovek   implements Demo
{
    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  technologie(){
      echo "Dávám přednost hartware";
   }

    public function behej($vzdalenost)
    {
         if ($this->unava + $vzdalenost <= 20){
            $this->unava += $vzdalenost;
            echo( 'Jsem v pohodě.');
         }else{
            echo('Jsem příliš unavený.');
         }
    }

    public function pozdrav()
    {
        echo('Ahoj, já jsem ' . $this->jmeno .' ' .$this->prijmeni.' a je mi '.$this->vek.' let.<br>');
    }


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

class Javista extends Clovek  implements Demo
{
    public $ide;
    public function __construct($jmeno, $prijmeni, $vek, $ide)
    {
        $this->ide = $ide;
        parent::__construct($jmeno, $prijmeni, $vek);
    }

     public function  technologie(){
      echo "Dávám přednost software";
   }


    public function programuj()
    {
        echo("Programuji v $this->ide .");
    }
}
        $karel = new Clovek('Karel', 'Novák', 30);
        $karel->pozdrav();
        $karel->behej(10);
        echo('<br>');
        $karel->technologie();
        echo('<br>');

        $jan = new Javista('Jan', 'Nový', 24, 'C_Plus');
        echo('<br>');
        $jan->pozdrav();
        $jan->behej(30);
        echo('<br>');
        $jan->technologie();
        echo('<br>');
        $jan->programuj();
 ?>

      Zdraví a krásne dny přeje
                                                             T.T.
 
Odpovědět
29. dubna 21:19
Avatar
Petr
Člen
Avatar
Petr:30. dubna 9:45

Což takhle začít využívat novinky php8.
Definice atributů třídy v konstruktoru.
Místo...
public $jmeno;
použít definici v konstruktoru...

public function __construct($jme­no,...
public string $jmeno = $jmeno, ... atd

Usetříme spoustu řádků v deklaracích.

 
Odpovědět
30. dubna 9:45
Avatar
Milan Turyna
Redaktor
Avatar
Odpovídá na Petr
Milan Turyna:3. května 8:28

PHP 8 ještě není podporované na mnoha hostingách (myslím, že např. Forpsi) a proto by některé začátečníky mohlo zmást, proč jim kód v lekci nefunguje. Proto si myslím, že je zatím lepší volbou, použití starší metody, která je podporovaná všude. Nebylo by ale od věci napsat více kódů (pro všelijaké verze) a jako uživatel mít možnost rozkliknout si svojí verzi.

 
Odpovědět
3. května 8:28
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 47. Zobrazit vše