(hlavička webu)

Podmínky

V rámci základního kurzu jsme už mluvili o výrazech, proměnných a operátorech. Umíme s hodnotami a proměnnými dělat některé výpočty, volat funkce a předávat jim argumenty a výsledky výpočtů a funkcí si uložit do proměnných anebo je vypsat. Chybí ještě jedna důležitá věc, ke které se právě dostáváme: Jak ovlivnit chod samotného skriptu v závislosti na hodnotě nějaké proměnné nebo výsledku nějakého výrazu. Ukážeme si, jak provést či neprovést některou část skriptu v závislosti na hodnotě proměnné nebo výsledku výpočtu. Také uvidíme praktické využití datového typu boolean (logická hodnota).

Zápis podmínky v PHP

Podmínka začíná klíčovým slovem if, následuje v závorkách výraz nebo hodnota určující samotnou podmínku, která má být splněna a pak kód, který se provede v případě splnění podmínky. Očekává se, že hodnota nebo výsledek výrazu určující splnění podmínky bude typu boolean (logická hodnota). Pokud je jiného typu, přetypuje se (podle pravidel, o kterých jsme mluvili v kapitole o přetypování). Hodnota true se považuje za splnění podmínky, hodnota false za nesplnění.

Příklad:

<?php
$podminka = true;
if ($podminka) {
  echo "Podmínka byla splněna";
}
?>
Zkuste si uvedený kód uložit do kořene webu třeba jako soubor priklad_podminka.php a otevřít v prohlížeči ( http://localhost/priklad_podminka.php ). Mělo by se vypsat "Podmínka byla splněna". Pak zkuste hodnotu $podminka nastavit na false místo true. Nemělo by se vypsat nic. Jestliže je v bloku jediný příkaz, tak jako v příkladu výše, není povinné ho uzavírat do složených závorek. Když tedy složené závorky vynecháte, patří k podmínce jen první následující příkaz. Dávejte v takovém případě pozor na formátování kódu, protože při nevhodném formátování lze vytvořit matoucí kód:
<?php
// ukázka nevhodného formátování
$podminka = false;
if ($podminka)
echo "Něco "; // toto závisí na splnění podmínky
echo "Něco jiného "; // toto už k podmínce nepatří!
?>
Vhodnější formátování kódu v takovém případě je:
<?php
if ($podminka) {
  echo "Něco ";
} 
echo "Něco jiného ";
?>
S tím souvisí i další věc: Za definici podmínky nikdy nedávejte středník! Protože za definicí podmínky středník být nemá a zároveň středník ukončuje příkaz, vezme se jako prázdný příkaz a zároveň ukončí podmínku. Tato chyba je záludná, protože takový kód je sice logicky chybně, ale syntakticky správně a žádnou chybu nenahlásí. Ukázka:
<?php
$podminka = false;
// Středník na konci podmínky se vezme jako prázdný příkaz a ukončí podmínku
if ($podminka);
  // Nevznikne žádná chyba, ale následující text se vypíše vždy:
  echo "Podmínka byla splněna";
?>
Za blokem if může následovat klíčové slovo else a za ním kód, který se provede v případě, že podmínka naopak splněna není. V případě splnění podmínky se tedy provede blok if, v případě nesplnění blok else, je-li uveden. Příklad:
<?php
$text = "Ahoj!";
if (empty($text)) {
  echo "Text je prázdný";
}
else {
  echo "Text není prázdný";
}
?>
Opět můžete uvedený kód vyzkoušet tak jak je v příkladu a s prázdným řetězcem v $text. Připomeňme funkci empty, která vrátí true v případě, že proměnná je prázdná nebo není nastavena a jinak false.

Můžeme také vylepšit kód pro vložení souboru, který jsme si ukázali v [odkaz]kapitole o základech syntaxe[/odkaz]. Připomeňme si tedy kód druhy.php:

<?php
// vloží soubor prvni.php
include "prvni.php";
?>
V případě, že soubor prvni.php nebude existovat, generuje tento kód varování (warning). Řekněme, že bychom chtěli místo toho vypsat do stránky nějaké srozumitelné chybové hlášení. Použijeme k tomu funkci is_file, které se jako argument předává název souboru a funkce vrátí true v případě, že soubor existuje a false pokud neexistuje.
<?php
// vloží soubor prvni.php, pokud existuje
if (is_file("prvni.php")) {
  include "prvni.php";
} else {
  echo "Nepodařilo se najít pomocný soubor pro stránku!";
}
?>
Poměrně častá je specifická situace, kdy chcete do proměnné nastavit jednu ze dvou hodnot podle toho, jestli nějaká podmínka byla či nebyla splněna. V takových případech lze podmínku if-else nahradit takzvaným podmíněným operátorem. Tvoří ho otazník a dvojtečka ?: a jako jediný operátor v PHP má tři operandy: Nejdřív je podmínka, kterou chceme testovat. Následuje otazník a hodnota operátoru v případě, že podmínka je splněna (vrátí true). Pak dvojtečka a hodnota v případě, že podmínka splněna není (vrátí false). Například když budeme chtít vypsat uživateli hlášku o existenci určitého souboru:
<?php
$soubor = "prvni.php";
if (is_file($soubor)) {
  $hlaska = "Soubor je dostupný";
}
else {
  $hlaska = "Soubor nenalezen";
}
echo "Stav souboru $soubor: $hlaska";
?>
Stejný skript lze napsat s použitím podmíněného operátoru:
<?php
$soubor = "prvni.php";
$hlaska = is_file($soubor) ? "Soubor je dostupný" : "Soubor nenalezen";
echo "Stav souboru $soubor: $hlaska";
?>
Neo i bez použití proměnné $hlaska:
<?php
$soubor = "prvni.php";
echo "Stav souboru $soubor: ".(is_file($soubor) ? "Soubor je dostupný" : "Soubor nenalezen");
?>
(Všimněte si použití operátoru pro spojování řetězců a podmíněného operátoru pro vrácení správné hlášky.) Kód je kratší a pro pokročilejšího programátora i přehlednější. Pro začátečníka ale může naopak být složitější na pochopení. Komu to připadá moc složité, může použít klasické if-else, výsledek bude stejný. Naopak všechna if-else podmíněným operátorem nenahrazujte, podmíněný operátor je vhodný jen pro určité situace. Vždy mějte na paměti přehlednost a čitelnost kódu. Je lepší mít více řádků přehledného kódu, než se snažit za každou cenu zhušťovat kód na úkor přehlednosti. Byť v kódu roztaženém přes zbytečně mnoho řádků se někdy také špatně orientuje.

Když je řeč o přehlednosti kódu, může se stát, že při splnění podmínky nechcete udělat nic a máte jen kód pro nesplnění. Někdo v takovém případě nechá blok if prázdný a kód dá do bloku else. To nedělejte. Raději napište obrácenou podmínku a kód umístěte do bloku if. Pamatujte, že jakoukoli podmínku lze otočit operátorem negace (! před podmínkou). Například chceme vypsat hlášku o neexistenci souboru. Méně přehledné řešení:

<?php
// toto nedělejte
if (is_file("prvni.php")) {
} else {
  echo "Soubor nenalezen!";
}
?>
Lepší řešení je podmínku otočit:
<?php
if (!is_file("prvni.php")) {
  echo "Soubor nenalezen!";
}
?>

Rozlišení více než dvou situací

Zatím jsme rozlišovali jen to, zda podmínka je splněna, nebo není. Někdy ale potřebujete rozlišit situací více. Například číslo je větší, menší nebo rovno nějaké hodnotě. Pak můžete za podmínkou místo else uvést elseif, další podmínku a blok kódu. Tento kód se provede v případě, že není splněna podmínka bloku if a zároveň je splněna podmínka daného elseif. Takových částí může být i více za sebou a na konci může opět následovat blok else, který se provede, pokud není splněna ani jedna z předchozích podmínek. U podmínky, která obsahuje část if, jednu nebo více elseif a else se nejprve vyhodnotí podmínka u if a je-li splněna, provede se blok kódu za if a poté se pokračuje dalším příkazem za koncem celé podmínky (tj. všechny bloky elseif a else se přeskočí). Není-li podmínka splněna, vyhodnocují se postupně jednotlivé podmínky elseif v pořadí, v jakém jsou v kódu napsané a provede se první, jejíž podmínka je splněna. Není-li splněna ani jedna podmínka elseif, provede se blok else, je-li zadán. A aby to nebylo tak fádní, zároveň se podíváme na další užitečnou funkci, a sice date(). Funkce date() vrátí složky aktuálního data a času ve formátu, jaký je určen argumentem funkce. Argument funkce je řetězec, ve kterém jsou složky data a času symbolizované písmeny. Jejich přehled a význam najdete v [odkaz]manuálu[/odkaz] (měl by být pochopitelný i v angličtině). Datum a čas v českém formátu se zapíše date("j.n.Y G.i:s"); (den, tečka, měsíc, tečka, rok, mezera, hodiny, tečka, minuty, dvojtečka, sekundy, přičemž u minut a sekund mají jednociferná čísla úvodní nulu, např. 1.1.2013 0.00:00, případně date("d.m.Y H.i:s"); pro úvodní nuly i u dne, měsíce a hodin, tj. např.: 01.01.2013 00.00:00).

Ukažme si tedy kód, který vypíše denní dobu:

<?php
$hodina = date("G"); // date("G") vrátí aktuální hodinu
echo "Právě je ";
if ($hodina > 18){
  // Víc než 18, tedy 19-23
  echo "večer";
}
elseif ($hodina >= 12) {
  // Není vyšší hodina než 18, ale je 12 nebo víc, tedy 12.00-18.59
  echo "odpoledne";
}
elseif ($hodina >= 9) {
  // 9.00-11.59
  echo "dopoledne";
}
elseif ($hodina >= 5) {
  // 5.00-8.59
  echo "ráno";
}
else {
  // 0.00-4.59
  echo "noc";
}
?>
Někdy chcete testovat výčet hodnot nějaké proměnné. Například:
<?php
$cislo1 = 6;
$cislo2 = 2;
$vysledek = 0;
$operace = "+";

if ($operace == "+") { $vysledek = $cislo1 + $cislo2; } elseif ($operace == "-") { $vysledek = $cislo1 - $cislo2; } elseif ($operace == "*") { $vysledek = $cislo1 * $cislo2; } elseif ($operace == "/") { $vysledek = $cislo1 / $cislo2; } ?>

To může při větším počtu podmínek nepřehledné a náročné na údržbu. Proto existuje příkaz switch, kterým lze tento druh podmínek zjednodušit a zpřehlednit. Níže uvedený příklad dělá to samé jako výše uvedený.
<?php
$cislo1 = 6;
$cislo2 = 2;
$vysledek = 0;
$operace = "+";

switch ($operace) { case "+": $vysledek = $cislo1 + $cislo2; break; case "-": $vysledek = $cislo1 - $cislo2; break; case "*": $vysledek = $cislo1 * $cislo2; break; case "/": $vysledek = $cislo1 / $cislo2; break; } ?>

Podmínka se zapisuje klíčovým slovem switch, za kterým se uvede proměnná nebo výraz. Oproti příkazu if zde výsledek výrazu není bool, ale obvykle číslo nebo řetězec. Následují složené závorky a v nich seznam bloků case. Ty začínají klíčovým slovem case, za kterým následuje hodnota a dvojtečka. Tomu se říká tzv. návěští. Za ním je pak blok kódu, zakončený příkazem break. Vyhodnocení probíhá tak, že se vezme hodnota u switch a porovnává se s hodnotami jednotlivých case. V případě rozdílných datových typů se přetypuje (tak jak jsme rozebírali v kapitole o [odkaz]přetypování[/odkaz]), ale měli byste se snažit, aby hodnoty měly stejný datový typ. Zpracuje se první blok case, který má stejnou hodnotu jako je u switch. A stejně jako if...elseif lze zakončit blokem else, který se provede v případě, že žádná z podmínek není splněna, v případě switch má stejnou úlohu blok default. Zde se samozřejmě nepíše hodnota (nemá význam), jen návěští default, dvojtečka a blok kódu, který se provede, jestliže hodnota u switch neodpovídá žádné z hodnot case. PHP také umožňuje na konci bloku case vynechat příkaz break, čímž zpracování pokračuje sekvenčně dál, tedy "propadne" do následujícího case. Toto je v některých případech užitečné, ale pro začátečníka může být velice nepříjemné v případě, že příkaz break vynechá omylem. Proto dodržujte pravidlo, že pokud v bloku case záměrně vynecháváte příkaz break, vždy místo něj napište komentář, že byl vynechán záměrně Příklad "propadávání" a použití bloku default:
<?php
$cislo = 50;
$modulo = $cislo % 4; // operátor modulo, tedy zbytek po dělení
// číslo modulo 4 může být 0, 1, 2 nebo 3
switch ($modulo) {
  case 0 : echo "Číslo je dělitelné 4<br>";
    // break vynechán, propadává do další větve
  case 2 : // Číslo je dělitelné 2, pokud zbytek po dělení 4 je 0 nebo 2
    echo "Číslo je dělitelné 2<br>";
    break; // zde skončí case 0 a case 2
  default: // Pokud neplatí ani jedno z předchozího
    echo "Číslo není dělitelné 2 ani 4<br>";
    // na konci default break být nemusí
}
?>
Vyzkoušejte pro různé hodnoty proměnné $cislo.

Kromě podmínek existuje ještě další nástroj pro řízení toku skriptu, a sice cykly, o kterých si povíme v příští kapitole.

Vyzkoušejte si: 1. Definujte proměnnou obsahující číslo a napište podmínku, která vypíše, zda její hodnota je větší, menší nebo rovna 10. 2. Napište skript, který zjistí, kolik celých hodin zbývá do konce dne a vypíše "Do konce dne zbývá x hodin", přičemž slovo "hodin" bude ve správném tvaru (1 hodina, 2 hodiny atd.) Pokud nezbývá ani jedna celá hodina, napíše se "Méně než 1 hodina". Nápověda: Pro určení počtu hodin do konce dne můžete použít 23 - date("G"). 3. Napište skript, který vypíše aktuální datum (den a měsíc), ale měsíc bude slovy (tj. "ledna", "února", atd.) Nápověda: Číslo měsíce získáte přes date("n"); a číslo dne přes date("j"); Zkuste navrhnout řešení pomocí switch a, s využitím minulé kapitoly, řešení pomocí pole. Porovnejte, které řešení je lepší.

Řešení: 1. Jedno z možných řešení je například:

<?php
$cislo = 12;
echo "Číslo je ";
if ($cislo == 10) {
  echo "rovno 10";
} 
elseif ($cislo > 10) {
  echo "větší než 10";
} 
else {
  echo "menší než 10";
}
?>
Šlo by také použít dva vnořené podmíněné operátory a podmínku tím zhustit na jediný řádek. Je to ovšem na úkor přehlednosti kódu, takové řešení je náchylné k zanesení chyb a špatně se udržuje, proto ho nelze doporučit. Pro ilustraci:
<?php
$cislo = 12;
echo "Číslo je ";
echo ($cislo == 10) ? "rovno 10" : (($cislo > 10) ? "větší než 10" : "menší než 10");
?>
Druhý podmíněný operátor je vnořený do větve při nesplnění podmínky prvního podmíněného operátoru. Stačí ale např. zapomenout závorky kolem druhého podmíněného operátoru a kód nebude fungovat správně (vyzkoušejte pro číslo 10).

2. Možné řešení:

<?php
$zbyva = 23 - date("G");
$hlaska = "Do konce dne ";
switch ($zbyva) {
  case 0: 
     $hlaska = $hlaska. "zbývá méně než 1 hodina";
     break;
  case 1:   
     $hlaska = $hlaska. "zbývá 1 hodina";
     break;
  case 2: // propadne do case 4
  case 3: // propadne do case 4
  case 4:
    $hlaska = $hlaska."zbývají ".$zbyva." hodiny";
    break;
  default:
    $hlaska = $hlaska."zbývá ".$zbyva." hodin";
}
echo $hlaska;
?>
Samozřejmě by šlo použít if-elseif-else.

3. Možné řešení pomocí switch:

<?php
$mesic = date("n");

echo date("j"); switch ($mesic) { case 1: echo ". ledna"; break; case 2: echo ". února"; break; case 3: echo ". března"; break; case 4: echo ". dubna"; break; case 5: echo ". května"; break; case 6: echo ". června"; break; case 7: echo ". července"; break; case 8: echo ". srpna"; break; case 9: echo ". září"; break; case 10: echo ". října"; break; case 11: echo ". listopadu"; break; case 12: echo ". prosince"; break; } ?>

Možné řešení pomocí pole:
<?php
// Začneme od indexu 1 (výchozí je 0), aby číslo měsíce odpovídalo indexu v poli
$mesice = array(1 => "ledna", "února", "března", "dubna", "května", "června", 
          "července", "srpna", "září", "října", "listopadu", "prosince");
echo date("j").". ".$mesice[date("n")];
?>
Řešit takovéto výčty (měsíce, dny v týdnu a podobně) využitím pole je obvykle výhodnější. Jednak je kód kratší, ale hlavně lze pole definovat jen jednou a pak ho používat opakovaně na více místech.
(patička webu)