Lekce 9 - Statika v PHP
V předešlém cvičení, Řešené úlohy k 7.-8. lekci OOP v PHP, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešním PHP tutoriálu se seznámíme s velmi kontroverzní technikou - statikou.
POZOR! Dnešní lekce vám ukáže statiku, tedy
postupy, které v podstatě narušují objektový model. OOP je obsahuje jen pro
speciální případy a obecně platí, že vše jde napsat bez
statiky. Vždy musíme pečlivě zvážit, zda statiku opravdu
nutně potřebujeme. Obecně bych doporučoval statiku vůbec
nepoužívat, pokud si nejste naprosto jisti, co děláte. Podobně,
jako globální proměnné je statika v objektovém programování něco, co
umožňuje psát špatný kód a porušovat dobré praktiky. Znalosti použijte
s rozvahou, na světe bude potom méně zla.
Třídní prvky
V objektově orientovaném programování jsme již trochu sběhlí a proto víme, že aplikace je složená z množiny komunikujících objektů. Objekty jsou vždy instance, vytvořené podle nějaké třídy. Každá instance je unikátní a má svůj vnitřní stav (atributy) a schopnosti (metody).
Objektově orientované programování však kromě instančních prvků
umožňuje definovat i prvky třídní. Jedná se o atributy a metody, které
nepatří instanci, ale patří třídě. Třídní metodu tedy
voláme na třídě, místo na instanci a instanci vůbec nepotřebujeme.
Takovou metodu označíme klíčovým slovem static
a můžeme ji
zavolat odkudkoli z programu aniž bychom měli instanci. Zkusme si to na
jednoduchém příkladu.
Matematická třída
Vytvořme si ve složce tridy/
novou třídu
Matematika.php
. Do ní nejprve umístíme instanční metodu
naDruhou()
, jak jsme byli zvyklí doposud:
class Matematika { public function naDruhou(float $zaklad): float { return $zaklad * $zaklad; } }
V souboru index.php
si zkusme nechat vypočítat druhou mocninu
pomocí naší metody. Vytvoříme si instanci naší třídy
Matematika
a zavoláme na ní příslušnou metodu:
{PHP} require_once('tridy/Matematika.php'); $matematika = new Matematika(); echo($matematika->naDruhou(12));
{PHP} class Matematika { public function naDruhou(float $zaklad): float { return $zaklad * $zaklad; } }
Výstupem programu je samozřejmě číslo 144
, ale o ten tu
teď nejde. Představte si, že v nějaké výpočetní aplikaci používáte na
mnoha místech v mnoha třídách nějaké podobné pomocné výpočty. Bylo by
poněkud nepraktické stále tvořit nové instance nebo si předávat instanci
třídy Matematika
. Z toho důvodu uděláme metodu
naDruhou()
statickou. Upravme třídu Matematika na tuto
podobu:
class Matematika { public static function naDruhou(float $zaklad): float { return $zaklad * $zaklad; } }
V souboru index.php
odstraníme vytvoření instance a metodu
naDruhou()
budeme volat přímo na třídě
Matematika
. K volání třídních prvků nepoužíváme operátor
šipky (->
), ale čtyřtečku (::
):
{PHP} require_once('tridy/Matematika.php'); echo(Matematika::naDruhou(12));
{PHP} class Matematika { public static function naDruhou(float $zaklad): float { return $zaklad * $zaklad; } }
Metodu jsme zavolali bez instance. Dá se říci, že je také globální a viditelná odkudkoli, což může při špatném použití způsobit velmi špatnou čitelnost kódu (viz dále). Víme, že OOP se snaží spíše co nejvíce věcí skrývat. V tomto případě je to však v pořádku a dále v seriálu si vysvětlíme další správná i špatná užití.
Kombinace statických a instančních prvků
Třída nemusí obsahovat jen instanční nebo jen statické prvky, ale může obsahovat jejich kombinaci. Instanční prvky jsou poté přístupné jen na instanci, statické zase jen na třídě.
Číslování instancí
O statických prvcích můžeme zjednodušeně říci, že jsou společné
pro všechny instance, jelikož patří té jedné třídě. Vraťme se zas k
našim lidem a dejme tomu, že je budeme potřebovat číslovat. Každý
člověk bude mít atribut $id
, ve kterém bude unikátní číslo.
První vytvořený člověk bude mít $id=1
, druhý
$id=2
a tak dále. Kde ale uchovávat kolik lidí jsme již
vytvořili?
Pokud známe statiku, není nic jednoduššího než přidat do třídy
Clovek
statický atribut pocetLidi
, nastavený na
0
. Třída si tedy pamatuje kolik lidí bylo vytvořeno. Je to i
logicky správně, jelikož atribut je sdílený mezi všemi instancemi a proto
je na třídě. V konstruktoru člověka poté tento statický atribut vždy
zvýšíme o 1 a do instanční proměnné $id
dosadíme toto
číslo.
Třída Clovek
bude vypadat s touto malou úpravou
následovně:
class Clovek { private int $unava = 0; public int $id; private static int $pocetLidi = 0; public function __construct(public string $jmeno, public string $prijmeni, public int $vek) { self::$pocetLidi++; $this->id = self::$pocetLidi; } public function spi(int $doba): void { $this->unava -= $doba * 10; if ($this->unava < 0) $this->unava = 0; } public function behej(int $vzdalenost): void { if ($this->unava + $vzdalenost <= 20) $this->unava += $vzdalenost; else echo('Jsem příliš unavený.'); } public function pozdrav(): void { echo('Ahoj, já jsem ' . $this->jmeno); } protected function celeJmeno(): string { return $this->jmeno . ' ' . $this->prijmeni; } public function __toString(): string { return $this->jmeno . ' - ' . $this->id; } }
Při bližším pohledu vidíme 2 nové atributy, instanční
$id
a třídní $pocetLidi
.
V konstruktoru inkrementujeme (zvýšíme o 1) proměnnou
$pocetLidi
a hodnotu dosadíme nové instanci do jejího
$id
. Ke statickým prvkům se uvnitř třídy přistupuje pomocí
klíčového slova self
. Má podobný význam jako
$this
, které uchovávalo aktuální instanci, klíčové slovo
self
uchovává aktuální třídu. Matoucí může být, že se za
čtyřtečku na rozdíl od $this
píše dolar $
.
Poslední změna spočívá v metodě __toString()
, kde vracíme
i ID, abychom jednoduše viděli, že nám jejich přidělování funguje.
V souboru index.php
poupravíme cyklus tak, aby místo zdravení
lidi vypisoval. Pro úplnost dodávám i jejich tvoření:
{PHP} require_once('tridy/Clovek.php'); require_once('tridy/Javista.php'); $lide = array(); $lide[] = new Clovek('Karel', 'Novák', 30); $lide[] = new Javista('Jan', 'Nový', 24, 'Eclipse'); $lide[] = new Clovek('Josef', 'Nový', 50); $lide[] = new Javista('Tomáš', 'Marný', 28, 'NetBeans'); $lide[] = new Clovek('Marie', 'Nová', 32); foreach ($lide as $clovek) { echo($clovek . '<br />'); }
{PHP} class Clovek { private int $unava = 0; public int $id; private static int $pocetLidi = 0; public function __construct(public string $jmeno, public string $prijmeni, public int $vek) { self::$pocetLidi++; $this->id = self::$pocetLidi; } public function spi(int $doba): void { $this->unava -= $doba * 10; if ($this->unava < 0) $this->unava = 0; } public function behej(int $vzdalenost): void { if ($this->unava + $vzdalenost <= 20) $this->unava += $vzdalenost; else echo('Jsem příliš unavený.'); } public function pozdrav(): void { echo('Ahoj, já jsem ' . $this->jmeno); } protected function celeJmeno(): string { return $this->jmeno . ' ' . $this->prijmeni; } public function __toString(): string { return $this->jmeno . ' - ' . $this->id; } }
{PHP} class Javista extends Clovek { public function __construct(string $jmeno, string $prijmeni, int $vek, public string $ide) { parent::__construct($jmeno, $prijmeni, $vek); } public function programuj(): void { echo("Programuji v {$this->ide}..."); } public function pozdrav(): void { echo('Hello world! Jsem ' . $this->jmeno); } }
Výstup programu:
Vidíme, že statický atribut $pocetLidi
opravdu náleží
třídě Clovek
. Když PHP třídu poprvé načte, vytvoří
atribut a nastaví do něj hodnotu 0
. Statický atribut na třídě
Clovek
v paměti přetrvává do skončení skriptu bez ohledu na
to, zda existují nějaké instance lidí nebo ne. S jeho hodnotou můžeme
manipulovat z instančních metod (zde z konstruktoru). Ze statické
metody nelze volat metoda instanční, jelikož k tomu potřebujeme
instanci Naopak to tedy
nelze.
Bez statiky by se tento příklad řešil pomocí objektu, který by lidi vyráběl. Takovým objektům se říká továrny, ale o tom zas někdy jindy.
Statika je velmi důležitá, velmi používaná a často velmi mylně chápaná programátorská technika. Z toho důvodu ji věnujeme více času. Řekneme si kdy ji používat a kdy nikoli. Budete na ni narážet často a je velmi důležité, abyste chápali jak funguje. Soubory z dnešní lekce jsou jako vždy ke stažení v archivu níže.
V příští lekci, Třídní prvky v PHP podruhé - konstanty, si vysvětlíme jak se v PHP používají konstanty.
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 597x (3.84 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP