Lekce 3 - Atributy a magické metody v PHP
V minulé lekci, První objektová aplikace v PHP, jsme si vysvětlili, jak OOP funguje a vytvořili jsme si první jednoduchou objektovou aplikaci.
Dnes si vysvětlíme atributy a základní magické metody.
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 string $jmeno; public string $prijmeni; public int $vek; . . .
Již víme, že atributy fungují jako proměnné, ale náleží objektu.
Modifikátor přístupu 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() : void { 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:
<?php require_once('tridy/Clovek.php'); $karel = new Clovek(); $karel->jmeno = 'Karel'; $karel->prijmeni = 'Novák'; $karel->vek = 30; $karel->pozdrav();
<?php class Clovek { public string $jmeno; public string $prijmeni; public int $vek; public function pozdrav() : void { echo('Ahoj, já jsem ' . $this->jmeno); } }
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:
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 ITnetwork</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>
<?php class Clovek { public string $jmeno; public string $prijmeni; public int $vek; public function pozdrav() : void { echo('Ahoj, já jsem ' . $this->jmeno); } }
Výstup aplikace vypadá takto:
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:
- Lze vytvořit nenastavený objekt a pracovat s ním, což jistě vyvolá chyby, např. při vypsání jména, které není zadané.
- 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(string $jmeno, string $prijmeni, int $vek) { $this->jmeno = $jmeno; $this->prijmeni = $prijmeni; $this->vek = $vek; }
Konstruktor nemá návratový datový typ, to samé platí i pro destruktor.
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:
<?php 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 />');
<?php class Clovek { public string $jmeno; public string $prijmeni; public int $vek; public function __construct(string $jmeno, string $prijmeni, int $vek) { $this->jmeno = $jmeno; $this->prijmeni = $prijmeni; $this->vek = $vek; } public function pozdrav() : void { echo('Ahoj, já jsem ' . $this->jmeno); } }
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ě.
Definice vlastností
V PHP 8 lze konstruktor využít i k přímé deklaraci a definici vlastností objektu. Asi jste si všimli, že v kódu výše jsme napsali jména všech vlastností třikrát:
- Při deklaraci vlastností
- V parametrech konstruktoru
- V těle konstruktoru při definici vlastností
Nyní se můžeme prvního a třetího bodu zbavit, a využít ke všemu parametry konstruktoru:
<?php 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 />');
<?php class Clovek { public function __construct(public string $jmeno, public string $prijmeni, public int $vek) {} public function pozdrav() : void { echo('Ahoj, já jsem ' . $this->jmeno); } }
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 z paměti:
<?php class Clovek { public function __construct(public string $jmeno, public string $prijmeni, public int $vek) {} public function pozdrav() : void { echo('Ahoj, já jsem ' . $this->jmeno); } public function __destruct() { echo('Byl jsem odstraněn z paměti.'); } }
<?php 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 />');
Když nyní aplikace spustíme, uvidíme, že úplně na konci se vypíše 2x hláška "Byl jsem odstraněn z paměti.":
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.
Předčasně můžeme destruktor spustit zničením objektu pomocí metody
unset()
.
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() : string { 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í - o tom ale jindy
. Dnešní projekt máte jako
vždy v příloze spolu se zdrojovými kódy.
V následujícím cvičení, Řešené úlohy k 1.-3. lekci OOP v PHP, si procvičíme nabyté zkušenosti z předchozích lekcí.
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 1526x (862 B)
Aplikace je včetně zdrojových kódů v jazyce PHP