3. díl - Atributy a magické metody v PHP

PHP Objektově orientované programování Atributy a magické metody v PHP American English version English version

V minulém dílu našeho seriálu tutoriálů o objektově orientovaném programování v PHP jsem si vysvětlili jak OOP funguje a vytvořili jsme si první jednoduchou objektovou aplikaci. V té budeme dnes pokračovat.

Atributy

Naše třída Clovek má zatím pouze metody (dokonce jen jednu). Přidejme jí nějaké atributy. Každý náš člověk bude mít jméno, příjmení a věk. Atributy třídě přidáme následovně:

<?php

class Clovek
{

        public $jmeno;
        public $prijmeni;
        public $vek;

        . . .

Již víme, že atributy fungují jako proměnné, ale náleží objektu. Public před názvem atributu označuje, že je atribut viditelný zvenčí (stejně jako tomu bylo u metody).

Abychom si atributy vyzkoušeli, upravíme si naši metodu pozdrav(). Budeme chtít, aby pozdravila "Ahoj, já jsem " a k tomu dodala hodnotu z atributu $jmeno. Budeme tedy chtít uvnitř metody použít atribut instance. Zajímavá otázka je, kde tu instanci vezmeme, jelikož třída je vzor společný pro všechny objekty daného typu (pro všechny lidi). Řešení je velmi jednoduché, ve třídě můžeme používat klíčové slovo $this. Pod touto proměnnou se skrývá instance, se kterou zrovna pracujeme a na které je tedy metoda volána. Metoda pozdrav bude nyní vypadat následovně:

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

Přesuňme se nyní do index.php, kde tvoříme instanci. Nyní ji nastavíme atributy, které jsme třídě Clovek dodali:

$karel = new Clovek();
$karel->jmeno = 'Karel';
$karel->prijmeni = 'Novák';
$karel->vek = 30;
$karel->pozdrav();

Do index.php si dodejme ještě HTML hlavičku, aby nám aplikace uměla česky. Když ji nyní spustíme, vidíme, že metoda opravdu přistoupila k atributu a vypsala jeho hodnotu.

Atributy v PHP

Abychom si vyzkoušeli, že je třída univerzální, vytvořme si ještě Jana. Celý kód indexu včetně HTML bude vypadat takto:

<!DOCTYPE html>

<html lang="cs-cz">
    <head>
            <meta charset="utf-8" />
            <title>OOP na devbooku</title>
    </head>

    <body>
        <?php
        require_once('tridy/Clovek.php');

        $karel = new Clovek();
        $karel->jmeno = 'Karel';
        $karel->prijmeni = 'Novák';
        $karel->vek = 30;

        $jan = new Clovek();
        $jan->jmeno = 'Jan';
        $jan->prijmeni = 'Nový';
        $jan->vek = 24;

        $karel->pozdrav();
        echo('<br />');
        $jan->pozdrav();

        ?>
    </body>
</html>

Výstup aplikace vypadá takto:

Instance třídy v PHP

Objekty jsou vysoce univerzální komponenty, stačí vytvořit společnou třídu a poté můžeme pracovat s různě nastavenými instancemi různým způsobem. A tím to zdaleka nekončí, uvidíte, že toho umí ještě spoustu.

Magické metody

PHP nám ve třídě umožňuje definovat několik tzv. magických metod. Magických proto, že si je nevoláme my sami (i když samozřejmě také můžeme), ale spouští se v určitých chvílích automaticky. Reagují tedy na určité události. Všechny magické metody začínají na dvě podtržítka. Je jich několik, ale my si zatím zmíníme první 3.

Konstruktor

V našem programu si nejprve vytváříme prázdnou (nenastavenou) instanci člověka a až poté mu nastavujeme jméno, příjmení a věk. To má hned několik nevýhod, zejména:

  1. Lze vytvořit nenastavený objekt a pracovat s ním, což jistě vyvolá chyby, např. při vypsání jména, které není zadané.
  2. Nastavení všech hodnot objektu zabírá zbytečně místo ve zdrojovém kódu.

Tento problém za nás řeší konstruktor. Konstruktor je metoda, která se automaticky spustí při vytvoření instance. Slouží k nastavení vnitřního stavu objektu tak, aby byl připraven k použití. Pokud má naše třída konstruktor, nelze její instanci vytvořit jinak, než právě použitím konstruktoru.

Konstruktor je metoda se jménem __construct() a s libovolným počtem parametrů. Přidejme si ho do naší třídy a jako parametry mu dejme $jmeno, $prijmeni a $vek. Hodnoty z parametrů nastavíme atributům instance:

public function __construct($jmeno, $prijmeni, $vek)
{
        $this->jmeno = $jmeno;
        $this->prijmeni = $prijmeni;
        $this->vek = $vek;
}

Konstruktor do třídy vložíme za atributy a před ostatní metody. Když nyní naši aplikaci spustíme, tak nebude fungovat. Je to z toho důvodu, že třída má nyní konstruktor a ten vyžaduje určité parametry, které jsme při vytváření instancí nezadali. Vidíme, že nás PHP nenechá vytvořit objekt jinak, než předepisuje konstruktor.

Přejděme do index.php a modifikujme PHP kód do následující podoby:

require_once('tridy/Clovek.php');

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

$karel->pozdrav();
echo('<br />');
$jan->pozdrav();
echo('<br />');

První dojem je zvýšení přehlednosti kódu. Vidíme, že ona záhadná závorka za třídou při vytváření její instance slouží k předání parametrů konstruktoru. Konstruktor následně tyto parametry uloží do objektu a tím ho připraví k použití. Využití konstruktoru samozřejmě není omezeno jen na nastavování atributů, můžeme v něm udělat cokoli jako v běžné metodě. Konstruktor můžeme definovat i bez parametrů, např. si v něm někam uložíme čas kdy byla instance vytvořena a podobně.

Destruktor

Pro úplnost si uveďme i destruktor. Jak vás asi napadlo, destruktor je metoda, která se zavolá ve chvíli, když se objekt odstraňuje z paměti. Můžeme zde provést nějaké úklidové práce, které jsou potřeba k uvolnění zdrojů, které objekt využíval. Jelikož skripty v PHP běží jen chvíli a poté se veškerá paměť, kterou skript využíval, uvolní, nemají destruktory příliš velký význam. Přesto je můžeme využít např. k uložení dat do databáze před zrušením nějakého objektu nebo databáze může před zrušením ukončit databázové spojení a podobně. Vy v současné době destruktor asi nevyužijete, ale patří ke konstruktoru, tak proč si ho nevyzkoušet.

Metoda destruktoru se jmenuje __destruct(). Vypišme v ní hlášku o tom, že se objekt odstranil zs paměti:

public function __destruct()
{
        echo('Byl jsem odstraněn z paměti.');
}

Když nyní aplikace spustíme, uvidíme, že úplně na konci se vypíše 2x hláška "Byl jsem odstraněn z paměti.".

Destruktory v PHP

Hlášku vypíší před svým zničením $karel a $jan, k jejich odstranění z paměti dojde až při ukončení aplikace nebo přesněji ve chvíli, když je již nemá smysl uchovávat.

Destruktor můžeme z naší třídy zase odebrat.

ToString

Magická metoda __toString() se spouští ve chvíli, kdy chceme objekt převést na textový řetězec, nejčastěji tedy když ho chceme vypsat. Schválně si zkuste nyní vypsat objekt $karel:

echo($karel);

PHP vám vyhodí chybu, jelikož není definované jakým způsobem se mají lidé vypisovat. Lidé jsou objekty, které mají několik vlastností, PHP jednoduše neví které z nich vypsat. Doplňme tedy do naší třídy Clovek metodu __toString(), která bude vracet atribut jméno.

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

Pokud se nyní znovu pokusíme Karla nebo Jana vypsat, vypíše se jednoduše jejich jméno.

Konstruktory nám umožňují provádět tzv. zapouzdření, ke kterému se dostaneme příště. Dnešní projekt máte jako vždy v příloze spolu se zdrojovými kódy.


 

Stáhnout

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

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (34 hlasů) :
4.882364.882364.882364.882364.88236


 



 

 

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

Avatar
Martin Konečný (pavelco1998):

Radím spíš naslepo, protože se v tomhle taky moc nevyznám, ale můžeš zkusit ještě tohle:

ini_set('display_errors', '1');
 
Odpovědět 1.8.2014 11:30
Avatar
Dominik Gavrecký:

Nerozumiem tomu publicu ... Kedy ho používať pretože vidno ho z vonku je vážne skrátene vysvetlenie.

Odpovědět 4.7.2015 0:32
Hlupák nie je ten kto niečo nevie, hlupákom sa stávaš v momente keď sa na to bojíš opýtať.
Avatar
Odpovídá na Dominik Gavrecký
Martin Konečný (pavelco1998):

Public se používá v podstatě ve dvou případech:

  1. hodnotu vlastnosti nastavujeme odjinud (třeba z jiného objektu)
  2. jsme líní psát settery a gettery

V určitých případech je to i nutné kvůli nějaké magii, ale to je na trochu jiném levelu

 
Odpovědět 4.7.2015 0:35
Avatar
Odpovídá na Dominik Gavrecký
Ondřej Štorc:

Čemu na tom nerozumíš když máš například tuhle třídu:

class Clovek {
     public $jmeno;
     private $pohlavi

Tak můžeš udělat tohle:

$ondra = new Clovek();
echo($ondra->jmeno);

ale už nemůžeš udělat tohle:

$ondra = new Clovek();
echo($ondra->pohlavi);
Odpovědět  +2 4.7.2015 0:38
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Odpovídá na Ondřej Štorc
Dominik Gavrecký:

Dakujem toto mi celkom pomohlo ...

Odpovědět 4.7.2015 6:33
Hlupák nie je ten kto niečo nevie, hlupákom sa stávaš v momente keď sa na to bojíš opýtať.
Avatar
Bebbana
Člen
Avatar
Bebbana:

Tak jsem se zasekla :(
Clovek.php :

<?php

    class Clovek
    {

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

a index.php:

!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <?php
        require_once('tridy/Clovek.php');

        $karel = new Clovek();
        $karel->jmeno = 'Karel';
        $karel->prijmeni = 'Novák';
        $karel->vek = 30;
        $karel->pozdrav();
    ?>
    </body>
</html>

A po spuštení mi to vypíše jenom: "Ahoj, já jsem" a nic víc. Přitom mám vše přesně jak v článku, třídu Člověk ve složce tridy a zkoušela jsem to jak na localhostu, tak na endoře, výsledek stejnej. Díky za radu.

 
Odpovědět 2.10.2015 1:46
Avatar
Jakub Novák
Člen
Avatar
Odpovídá na Bebbana
Jakub Novák:

Tak sem asi posíláš jiný kód, protože tenhle je funkční.

Zkus tohle :

<?php

class Person
{
        /** @var string */
        private $name;

        /** @var string */
        private $surname;

        /** @var string */
        private $age;

        public function sayHello()
        {
                print("Hi, I'm $this->name $this->surname and I'm $this->age years old.");
        }

        public function __set($var, $value)
        {
                $this->$var = $value;
        }

        public function __get($var)
        {
                return $this->$var;
        }
}
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <?php

        $person = new Person();
        $person->name = "Karel";
        $person->surname = "Novák";
        $person->age = 21;
        $person->sayHello();
    ?>
    </body>
</html>

V budoucnu místo 30ti public vars můžeš použít magické metody GET a SET, stejně jako jsem použil já teď (nebude našeptávač). Víc si o tom můžeš přečíst třeba tady http://php.net/…p5.magic.php. Je určitě dobré vědět, že existujou a nenarušovat zapouzdření objektů + můžeš místo magických metod používat vlastní gettery a settery. Co si ale budeme nalhávat, skoro každý programátor používá public vars protože to jsou líný čuníci (včetně mě) a každý řádek navíc je zbytečná ztráta času.

 
Odpovědět 2.10.2015 2:12
Avatar
pradedadedymraze:

Nic ti to nepíše, protože vytváříš karla a voláš konstruktor bez parametru

$karel = new Clovek();

- tedy vytvoříš objekt karel ale nenastavíš jméno, příjmení ani věk. Musíš to volat takto:

$karel = new Clovek("Arnošt","Pátek",30);
 
Odpovědět 23. dubna 1:12
Avatar
pradedadedymraze:

Jinak celkem pěkně se tyhle pokusy ladí třeba zde: http://www.runphponline.com/

 
Odpovědět 23. dubna 1:13
Avatar
Pavel Parma
Člen
Avatar
Odpovídá na Jakub Novák
Pavel Parma:

Ohledně těch našeptávačů, PhpStorm povoluje annotace, které pomáhají určit i magicky nastavené proměnné. Je to @property-read @property-write a @property (ta je read i write), annotace následuje datovým typem a pak názvem attributu jako proměnné (např. $foo). Existuje dokonce i annotace pro magicke metody @method. Tady máte kdyžtak seznam používaných annotací, jelikož je to pro php jen nevyužívaný string, vytažitelný reflekcí, záleží na konkrétním IDE, zda je využívá nebo ne.

https://manual.phpdoc.org/…rty.pkg.html

 
Odpovědět 23. dubna 2:10
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 68. Zobrazit vše