10. díl - Třídní prvky v PHP podruhé - konstanty

PHP Objektově orientované programování Třídní prvky v PHP podruhé - konstanty American English version English version

V minulém tutoriálu o objektově orientovaném programování v PHP jsme si uvedli statiku a ukázali dvě její praktická využití. Dnes budeme v podobném duchu pokračovat a řekneme si ještě více o třídních prvcích.

Ověření hesla

Rozšiřme ještě náš příklad z minula. Dejme tomu, že se naši lidé registrují do nějakého systému. Kromě svého jména zadávají ještě heslo. Než člověka vytvoříme, je nutné heslo ověřit, zda není moc krátké.

Metoda k ověření délky hesla k člověku logicky patří. Ve chvíli, kdy heslo ověřujeme (např. z formuláře) ale ještě nemáme člověka vytvořeného. Abychom ho vytvořili, potřebujeme znát jméno, příjmení, věk a heslo, jelikož člověk je vyžaduje v konstruktoru. Abychom však zavolali metodu pro ověření hesla, potřebujeme mít vytvořenou instanci člověka. Problém vyřešíme tak, že metodu k ověření hesla napíšeme jako statickou. Tak ji budeme moci zavolat i bez instance a zároveň bude logicky zařazena ve třídě Clovek, kam patří.

Ověření je značně zjednodušené, v reálu by se ověřovalo zda heslo neobsahuje diakritiku a podobně. Třídě Clovek přidáme privátní instanční proměnnou $heslo. Proč je $heslo privátní snad nemusím vysvětlovat.

private $heslo;

Dále upravíme konstruktor tak, aby se uživatel mohl vytvořit jen se zadaným heslem:

public function __construct($jmeno, $prijmeni, $vek, $heslo)
{
        $this->jmeno = $jmeno;
        $this->prijmeni = $prijmeni;
        $this->vek = $vek;
        self::$pocetLidi++;
        $this->id = self::$pocetLidi;
        $this->heslo = $heslo;
}

Podobně upravte i konstruktor Javisty z minulých lekcí, aby se nám nerozbil, ještě ho budeme potřebovat.

Heslo by se mělo nějaký způsobem hashovat, nyní to pro jednoduchost zanedbáme, podrobněji se to řeší v dalších seriálech. Třídě nakonec přidejme statickou veřejnou metodu validniHeslo():

public static function validniHeslo($heslo)
{
        return (mb_strlen($heslo) >= 5);
}

Metoda vrátí true pokud je délka hesla větší než 5 znaků, jinak vrátí false. Až na použití funkce mb_strlen() v ní není nic zajímavého. Asi víte, že funkce mb_strlen() umí na rozdíl od zastaralé strlen() pracovat s kódováním UTF-8. Kódování pro tyto funkce však musíme v indexu nastavit. Někam na začátek tedy přidejme:

mb_internal_encoding("UTF-8");

Více informací o funkci naleznete v českém PHP manuálu.

V indexu si zkusíme jednoduše realizovat scénář registrace nového člověka do systému:

$heslo = 'heslojeveslo';
if (Clovek::validniHeslo($heslo))
        $clovek = new Clovek('Jan', 'Novák', 32, $heslo);
else
        echo('Heslo musí být dlouhé minimálně 5 znaků');

Validační metodu je možné volat bez instance, což se v naší situaci hodí.

Konstanty

Mezi třídní prvky patří také konstanty. Jak jistě z matematiky známe, jedná se o nějakou neměnnou hodnotu. Konstanty jsou vždy statické, ačkoli se před ně modifikátor static nepíše. Definují se klíčovým slovem const a patří vždy nějaké třídě. Jejich název se píše velkými písmeny, místo mezer se používají podtržítka. Píší se jako první ve třídě, ještě před atributy.

Konstanta Pí

Přidejme si konstantu PI do naší třídy Matematika.php z minula:

const PI = 3.14159265358979;

V index.php si ji zkusme použít:

$polomer = 5;
$obsah = Matematika::PI * Matematika::naDruhou($polomer);
echo("Obsah kruhu je $obsah cm<sup>2</sup>.");

Výsledek:

Konstanty v PHP

Konstanta minimální délky hesla

Konstanta se nám hned hodí pro minimální délku hesla. Když se ji někdy rozhodneme změnit nebo ji budeme chtít použít na více místech, bude přehledně definována jednou na začátku třídy. Přidejme k naší třídě Clovek.php konstantu DELKA_HESLA nastavenou na hodnotu 5:

const DELKA_HESLA = 5;

Nyní nahradíme pětku v metodě validniHeslo() za tuto konstantu. Jelikož se jedná o třídní prvek, použijeme k přístupu ke konstantě zevnitř třídy klíčové slovo self:

public static function validniHeslo($heslo)
{
        return (mb_strlen($heslo) >= self::DELKA_HESLA);
}

Program funguje jako dříve a důležitá konstanta je přehledně na začátku třídy. Ke konstantě můžeme samozřejmě opět přistupovat i mimo třídu:

echo('Vítejte v registraci, zvolte si uživatelské jméno a heslo o minimální délce ' . Clovek::DELKA_HESLA);

Konstanty bychom měli využívat ve svých aplikací pokaždé, když definujeme nějakou neměnnou hodnotu. Často je využívám pro různé limity, např. maximální počet událostí na člena:

const MAX_UDALOSTI = 50;

Výčtové typy (ENUM) v PHP

Konstanty se v PHP často využívají pro nahrazení tzv. výčtových typů, které PHP neobsahuje. Sice se dají nahradit pomocí tříd, ale používání konstant se uchytilo více, protože je to jednodušší.

Když máme v aplikaci proměnnou, která nabývá vždy jedné hodnoty z určitého výčtu hodnot, použijeme právě konstanty.

Typ zprávy

Ukažme si využití výčtových typů na reálném příkladu. Budeme uchovávat zprávu pro uživatele, kterou vygeneroval náš redakční systém. Zpráva může být buď informační (modrá s ikonkou i), chybová (červená s ikonkou křížku) nebo úspěšná (zelená s fajfkou).

K reprezentaci zprávy můžeme použít obyčejné asociativní pole, kde v klíči bude typ zprávy a v hodnotě její text. Bez znalostí konstant bychom asi použili k uchování typu textový řetězec:

$zprava = array(
        'typ' => 'uspech',
        'text' => 'Článek byl publikován',
);

Takovéto zprávě potom podle typu přiřadíme CSS třídu, můžeme je podle typu řadit a podobně. Abychom nemuseli přemýšlet nad tím, zda jsme zvolili hodnotu "uspech", "uspesna" nebo "ok", uděláme si na hodnoty z výčtu konstanty. Konstanty budou přehledně na třídě, která zprávy zpracovává a IDE nám je bude i napovídat:

class SpravceZprav
{
        const TYP_INFO = 0;
        const TYP_USPECH = 1;
        const TYP_CHYBA = 2;

        public function pridejZpravu($typ, $text)
        {
                . . .
}

Vše je přehlednější. Výše vidíte náznak třídy, jejíž metoda pridejZpravu() vytvoří pole se zprávou a to si uloží. Vnitřní mechanismus jsem zde pro jednoduchost zanedbal. Metoda pridejZpravu() by se volala asi takto:

$spravceZprav = new SpravceZprav();
$spravceZprav->pridejZpravu(SpravceZprav::TYP_USPECH, 'Článek byl publikován');

Podobná třída je opravdu použita v seriálu o tvorbě MVC objektového redakčního systému v PHP k zobrazování zpráv uživateli. Časem se tam jistě dostanete :)

Pozn. : Konstanty se ve starých neobjektových verzích PHP definovaly pomocí funkce define(). Taková konstanta nepatřila žádné třídě a trpěla nedostatky neobjektového programování, které jsme si zmiňovali v začátcích seriálu.

I příští lekci budeme věnovat statice, ukážeme si využití statického databázového wrapperu, statického registru a pobavíme se více teoreticky o správných a špatných využitích třídních prvků. Soubory z dnešní lekce jsou jako vždy ke stažení v archivu níže.


 

Stáhnout

Staženo 469x (1.91 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

  Aktivity (2)

Č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 (9 hlasů) :
55555


 


Miniatura
Předchozí článek
Statika v PHP
Miniatura
Následující článek
Statika v PHP do třetice

 

 

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

Avatar
Marek Šafránek:

Zdravím,

věděl by prosím někdo proč se mi zobrazuje chyba při otevření index.php(pokud udělám přímé require bez autoloaderu, funguje jak má, funguje i nadále, pokud do kodu vrátím na místo přímého require autoloader):

Fatal error: Undefined class constant 'DELKA_HESLA'

___
class Clovek
{

        const DELKA_HESLA = 5;
        public $jmeno;
        public $prijmeni;
        public $vek;
        private $unava = 0;
        public $id;
        private static $pocetLidi = 0;
        private $heslo;
...

___
<?php

        function nactiTridu($trida)
        {
                require("tridy/$trida.php");
        }

        spl_autoload_register("nactiTridu");


        mb_internal_encoding("UTF-8");

        echo('Vítejte v registraci, zvolte si uživatelské jméno a heslo o minimální délce ' . Clovek::DELKA_HESLA);
Odpovědět 15.1.2015 15:02
Stojí-li něco za námahu, je třeba to udělat pořádně...
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Marek Šafránek
Matúš Petrofčík:

skús niečo ako

<?php

        function nactiTridu($trida)
        {
                require("tridy/$trida.php");
        }

        spl_autoload_register("nactiTridu");


        mb_internal_encoding("UTF-8");

        $delka_hesla = Clovek::DELKA_HESLA; // najprv si tú premennú získať

        echo('Vítejte v registraci, zvolte si uživatelské jméno a heslo o minimální délce ' . $delka_hesla); // až tak ju vypísať
Odpovědět 15.1.2015 15:27
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Martin Franta:

Měl bych otázku ohledně logiky - v článku se píše, že funkce validniHeslo logicky patří pod třídu Clovek. Pokud bysme se však nebavili o ukázkové app, ale větším projektu, kde máme desítky různých typů validací tak nemělo by větší logiku vytvořit třídu Validator která bude obsahovat všechny možné kontroly/validace a budeme je tak mít pohromadě?
Pokud bych to měl aplikovat na tento příklad tak dejme tomu, že kromě třídy Clovek budeme mít ještě třídu Ufon, která nebude Cloveka rozšiřovat, ale bude naprosto rozdílná. Přitom heslo budeme chtít od obou a budeme vyžadovat stejné podmínky. Potom když budeme pracovat s Ufonem tak mi přijde logičtější volat Validator->heslo($heslo) než do toho motat Cloveka a volat Clovek::valid­niHeslo($heslo)
V OOP si teprve doplňuju mezery protože sem byl několik let zaseknutý na větším projektu, který nebyl napsaný objektově a nebyl čas jej přepisovat. Snažím se proto především zvyknout si na rozdílný způsob myšlení abych nedělal v objektech nesmysly, takže budu rád za jakoukoliv konstruktivní poznámku k situaci co sem uvedl :)

 
Odpovědět 30.4.2015 13:34
Avatar
Odpovídá na Martin Franta
Martin Konečný (pavelco1998):

Buď si uděláš třídu určenou pro hesla (třeba Passwords), případně by měla jít i ta tvá Validators.
Třetí možnost je, aby třídy Clovek i Ufon dědily od třídy, která by danou metodu obsahovala (třeba Bytost :D).

 
Odpovědět  +1 30.4.2015 13:48
Avatar
loading84
Člen
Avatar
loading84:

Na xampu mi tenhle kod funguje na serveru nikoliv. Nema někdo nějaky napad co nastavit v php.ini

$polomer = 5;
$obsah = Matematika::PI * Matematika::naDruhou($polomer);
echo("Obsah kruhu je $obsah cm<sup>2</sup>.");
 
Odpovědět 12.10.2015 15:54
Avatar
loading84
Člen
Avatar
Odpovídá na loading84
loading84:

vyřešeno, omlouva se za spam... měl jsem před tím

echo $pavla->celeJmeno();

s tim ze celeJmeno je protected. Tak mi to nebralo posledni radky.

 
Odpovědět 12.10.2015 16:21
Avatar
loading84
Člen
Avatar
loading84:

Nechápu proč mi funguje Javista když heslo ma status

$private

Jedině snad proto, že je v konstruktoru.

 
Odpovědět 9.11.2015 17:15
Avatar
 
Odpovědět 9.11.2015 17:20
Avatar
loading84
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
loading84:

Vytvoření instance, protože to mám v konstruktoru. Je možné že nerozumím použití private, protected a public.. nebo spíše public mi je jasný, ale po tomhle mám pochybnosti jestli rozumím atributum private a protected.

 
Odpovědět 9.11.2015 17:24
Avatar
Odpovídá na loading84
Martin Konečný (pavelco1998):

Když je atribut public, můžeš ho přímo použít odkudkoliv (ze třídy, z potomka nebo zvenku), protected jen ze třídy a z potomka a private jen ze třídy.

class Neco
{

        public $a;
        protected $b;
        private $c;


        public function akce()
        {
                echo $n->a;  // OK
                echo $n->b;  // OK
                echo $n->c;  // OK
        }

}

$n = new Neco();
echo $n->a;  // OK
echo $n->b;  // error
echo $n->c;  // error


class Potomek extends Neco
{

        public function akce()
        {
                echo $n->a;  // OK
                echo $n->b;  // OK
                echo $n->c;  // error
        }

}
 
Odpovědět 9.11.2015 17:46
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 33. Zobrazit vše