C/C++ week November Black Friday
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Pouze tento týden sleva až 80 % na e-learning týkající se C/C++

Lekce 3 - Atributy a magické metody v PHP

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, První objektová aplikace v PHP, jsme si vysvětlili jak OOP funguje a vytvořili jsme si první jednoduchou objektovou aplikaci. V té budeme dnes v PHP tutoriálu 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:

<?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 $jmeno;
    public $prijmeni;
    public $vek;

    public function pozdrav()
    {
        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.

Your page
localhost

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 $jmeno;
    public $prijmeni;
    public $vek;

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

}

Výstup aplikace vypadá takto:

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

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:

<?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 $jmeno;
    public $prijmeni;
    public $vek;

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

    public function pozdrav()
    {
        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ě.

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

Your page
localhost

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. V příští lekci, Zapouzdření v PHP, se budeme věnovat zapouzdření.


 

Stáhnout

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

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
52 hlasů
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 sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
První objektová aplikace v PHP
Všechny články v sekci
Objektově orientované programování (OOP) v PHP
Miniatura
Následující článek
Cvičení k 1.-3. lekci OOP v PHP
Aktivity (13)

 

 

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

Avatar
pradedadedymraze:23.4.2016 1:12

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.4.2016 1:12
Avatar
pradedadedymraze:23.4.2016 1:13

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

 
Odpovědět
23.4.2016 1:13
Avatar
Pavel Parma
Člen
Avatar
Pavel Parma:23.4.2016 2:10

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.4.2016 2:10
Avatar
Adam Černohous:11.1.2017 10:24

Musím vždycky ve třídě definovat její atributy, když mám konstruktor, který se o to postará? Protože to funguje i bez nich.

Např.:

public $firstname; // atributy tridy, funguje to bez nich
public $lastname; // atributy tridy, funguje to bez nich
public $age; // atributy tridy, funguje to bez nich

public function __construct($firstname, $lastname, $age) {
    $this->firstname = $firstname;
    $this->lastname = $lastname;
    $this->age = $age;

    }

Díky moc!

 
Odpovědět
11.1.2017 10:24
Avatar
Pavel Bartoš:24.7.2017 9:17

Ahoj chtěl bych se zeptat, jestli je možné používat v těle třídy funkci, která si bere jako parametr proměnnou, jelikož jsem tu zatím viděl jen případy, kdy se používá některá proměnná z atributů třídy a to napevno až v samotnem těle funkce... A může-li být ta proměnná z přijatá z vnějšku třídy, nebo musí být uvnitř třídy. A jestli musí, tak jestli musí být public, nebo private.

Např:
$cislo=10;
$Pocitacka= new pocitacka();
$pocitacka->pocitej($cislo);

Šlo by to nebo ne?
Díky :-)

 
Odpovědět
24.7.2017 9:17
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jiří Zeman
Člen
Avatar
Jiří Zeman:1.10.2017 18:09

Chci se jen zeptat. Až bych dělal někdy nějaký projekt.... Používají se tam Destruktory? Takhle jako začátečníkovi mi to přijde celkem i zbytečné ho používat. Ale určitě bych chtěl slyšet nějakou odpověz od zkušeného PhP-čkaře.

Odpovědět
1.10.2017 18:09
Chybami se člověk učí.
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na Jiří Zeman
Jan Lupčík:1.10.2017 18:17

Zatím jsem používal destruktor jen jednou, a to když jsem potřeboval něco udělat po výpisu a zobrazení dat.

Odpovědět
1.10.2017 18:17
TruckersMP vývojář
Avatar
pmaly
Člen
Avatar
Odpovídá na Adam Černohous
pmaly:1.3.2018 22:13

Definice atributů
Konvence říká, že všechny atributy by měly být definovány na začátku definice třídy.

 
Odpovědět
1.3.2018 22:13
Avatar
Matěj Bína
Člen
Avatar
Matěj Bína:16. března 18:02

V textu to nevidím, ale jestli jsem to pochopil správně: když vytvořím atribut

public $neco;

tak se do něj dostanu skrz

$this->neco;
nebo
$instance->neco;

Nějak mě mate absence $ za ->, ale asi se s tím budu muset smířit.

Editováno 16. března 18:03
 
Odpovědět
16. března 18:02
Avatar
Odpovídá na Matěj Bína
Michal Šmahel:16. března 23:11

Ano, je tomu tak. Chápeš to správně.

Odpovědět
16. března 23:11
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
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 75. Zobrazit vše