V předminulém díle seriálu jsem ukázal, jak pomocí PHP jednoduše a komfortně zobrazit datum a čas pomocí dvou řádků skriptu. Nebylo by ale jednodušší místo těchto dvou řádků použít pouze jeden příkaz? V tomto díle si předvedeme, jak to udělat.

I když je v PHP už k dispozici velké množství nejrůznějších funkcí, často se nám bude hodit nadefinovat si také funkce vlastní. K čemu je to dobré? Za prvé ušetříme místo, pokud se nějaký kousek kódu ve skriptu často opakuje. Za druhé (a to je asi hlavní důvod, proč funkce používat) ušetříme čas při programování dalších aplikací – celé programování bude často spočívat v tom, že pouze překopírujeme už naprogramované funkce a napíšeme jen podstatně kratší skript, který jich bude využívat. Funkce pro již avizované vypsání aktuálního datumu bude vypadat třeba takto:

function Datum ()
{
$mesice = array („ledna“, „února“, „března“, „dubna“, „května“, „června“, „července“, „srpna“, „září“, „října“, „listopadu“, „prosince“);
return Date („j“) . „. “ . $mesice[Date („n“) – 1] . “ “ . Date („Y“) . „, “ . Date („H:i:s“);
}

Pokud budeme potřebovat kdekoliv ve skriptu vypsat aktuální datum, stačí nám jen dát echo Datum (). Funkce obvykle definujeme na samém začátku skriptu, určitě však dříve, než jsou poprvé použity (PHP4 už by mělo umožňovat i obrácené pořadí, ale logičtější je pochopitelně nejprve funkci definovat a až pak ji používat). Všimněte si dvojice prázdných závorek za názvem funkce v její definici. Normálně jsou zde obsaženy vstupní proměnné, naše funkce však žádný vstup nepotřebuje. Výstup funkce se definuje příkazem return – vše, co je za ním uvedeno, je výsledek, který dostaneme po provedení funkce zpět. Obecný formát definice funkce je tento:

function NazevFunkce ($promenna1, $promenna2, $promenna3)
{
příkazy;
return $vysledek;
}

Důležitou vlastností jazyka PHP je to, že všechny proměnné použité uvnitř funkce jsou lokální, tzn. jakékoliv operace s nimi se projeví právě jen uvnitř funkce, naopak funkce se nemůže dostat k obsahu proměnných, které používá hlavní skript, pokud jí nejsou předány (to není až tak úplná pravda, jak uvidíme dále).

Funkce je tak jakási černá skříňka, která komunikuje s hlavním skriptem pouze pomocí vstupů a výstupu. Můžete dokonce používat stejně pojmenovanou proměnnou ve funkci a v hlavním programu (rozhodně však kvůli přehlednosti nedoporučuji) a pokaždé půjde o jinou proměnnou. Aby byla tato teorie názornější, ukážeme si, jak může vypadat funkce, která vrací maximální hodnotu uloženou v poli (předpokládáme číselný index počínající nulou):

function Maximum ($pole)
{
$max = $pole[0]; for ($i = 0; $i < Count ($pole), $i++) if ($pole[$i] > $max) $pole[$i] = $max;
return $max
}

Řekněme, že máme ve skriptu k dispozici pole $cena, které obsahuje tyto hodnoty: $cena[0] = 199, $cena[1] = 249, $cena[2] = 219, $cena[3] = 399. Nyní, máme-li definovanou funkci pro maximální prvek pole, můžeme tento prvek lehce vypsat příkazem echo Maximum ($cena) (vypíše se 399). Vše pracuje takto: nejprve se přiřadí obsah pole $cena, které je funkci předáno, do pole nazvaného prozaicky $pole. To existuje jen uvnitř funkce. Do proměnné $max (ta také existuje právě jen po dobu běhu funkce) přiřadíme hodnotu nultého prvku, poté s touto dosavadní maximální hodnotou porovnáváme všechny prvky pole, pokud nalezneme větší, dáme ji do $max místo té, co tam už je.

Nyní je v $max maximální hodnota, tu vrátíme příkazem return. V tom okamžiku zaniknou všechny proměnné, které jsme použili ve funkci, máme k dispozici pouze výsledek (ten můžeme vypsat, přiřadit ho do nějaké proměnné apod.). Někdy budeme potřebovat, aby funkce manipulovala přímo s obsahy globálních proměných (to jsou ty, které používáme v hlavním skriptu). Jednou z možností, jak toho dosáhnout, je definovat ve funkci příkazem global, ke kterým proměnným má mít přístup. Tato definice vypadá takto:

function NazevFunkce ($lokalni1, $lokalni2, $lokalni3)
{
global $globalni1, $globalni2;
příkazy;
return $vysledek;
}

Nyní jsou proměnné $globalni1 a $globalni2 přístupné uvnitř funkce, můžeme využívat jejich hodnoty a projeví se na nich jakékoliv operace s nimi. Druhou možností je takzvané předávání odkazem (na rozdíl od předávání hodnotou, které jsme dělali doteď). Namísto toho, abychom funkci předali pouze nějakou hodnotu, se kterou pak funkce něco provede, předáme jí rovnou celou proměnnou – ve funkci se pak manipuluje přímo s ní, operace se tedy projeví i vně funkce. Že proměnnou předáváme odkazem, řekneme PHP pomocí znaku &&;, který je umístěn před proměnnou buď v definici vstupů funkce, nebo přímo před předávaným parametrem v samotném volání funkce. Mějme například definovanou takovouto funkci:

function Umocni (&&;$cislo)
{
return $cislo * $cislo;
}

Tato funkce bude pracovat přímo s proměnnou, posloupnost příkazů $a = 5; Umocni ($a); echo $a; vypíše 25. Co by se stalo, kdybychom v definici funkce znak &&; vynechali? Nejprve by se do $a přiřadilo 5, poté by se umocnila hodnota v $a, ovšem s tou bychom nic neudělali, a následný příkaz echo $a by vypsal 5. Kýženého výsledku 25 bychom se dobrali tak, že bychom použili echo Umocni ($a) nebo bychom to, že jde o předání odkazem, určili až při volání funkce (příkazy by tedy vypadaly takto: $a = 5; Umocni (&&;$a); echo $a;).

Pochopitelně uvnitř funkce je možné volat další funkce, které volají další funkce atd. Krajním případem takového zřetězeného volání je tzv. rekurze, kterou ti z vás, kteří už někdy programovali v jiném jazyku, pravděpodobně dobře znají. V podstatě jde o to, že funkce volá sama sebe, přičemž se úkol, který má, postupně zjednodušuje. Klasickým případem je faktoriál – úlohu spočítat faktoriál $n můžeme zjednodušit na výpočet faktoriálu ($n-1) vynásobeného $n (samozřejmě pokud počítáme faktoriál 0, musíme rovnou vrátit 1). Pokud budeme chtít naprogramovat takovýto rekurzivní výpočet faktoriálu, dostaneme přibližně toto:

function Faktorial ($n)
{
if ($n == 0):
return 1;
else:
return $n * Faktorial ($n – 1);
endif;
}

Pokud po definici zadáme např. echo Faktorial (6), bude funkce volat tak dlouho sama sebe, dokud se nedobere ke správnému výsledku, tj. 720. Rekurze je ovšem dost náročná na systémové zdroje, měli bychom ji proto používat pouze v odůvodněných případech (např. faktoriál jde jednoduššeji a nenáročněji spočítat pomocí cyklu).

Shrnutí anebo co si je třeba pamatovat

  • Definice vlastních funkcí nám při programování ušetří kromě prostoru hlavně čas, vede také k větší přehlednosti a strukturovanosti kódu.
  • Funkce bychom měli definovat na začátku skriptu, určitě však předtím, než je poprvé použijeme.
  • Všechny proměnné použité ve funkci jsou pouze lokální – funkce je černá skříňka, která s hlavním skriptem komunikuje pouze pomocí vstupů a výstupu.
  • Pokud přece jen chceme použít ve funkci globální proměnné, musíme je buď předat odkazem, nebo zpřístupnit příkazem global.
  • Funkce může volat i jiné funkce, pokud volá sama sebe, jde o rekurzi.

Už před časem jsme si ukázali dvě funkce pro práci s řetězci – Implode a Explode. V dalším díle (pravděpodobně v dalších dílech:o) se podíváme na práci s řetězci trochu podrobněji.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

4 Příspěvků v diskuzi

  1. Ta funkce Maximum je spatne napsana, jak syntakticky, tak hlavne semanticky.
    Nevraci maximalni prvek nybrz prvni prvek,. ; o)

  2. Narazil jsem na tenhle článek při hledání výpisu maxima z pole… a akorát mě to zdrželo, když je to špatně napsaný a autor to není schopný opravit… Tak třeba pro ostatní, kdo hledají řešení:

    pole třeba takhle:

    $cena[0] = 299;
    $cena[1] = 149;
    $cena[2] = 219;
    $cena[3] = 399;

    echo max($cena); // vypíše 399
    echo min($cena); // vypíše 149

    ani na to neni potřeba speciální funkce ;)

  3. Tak samozřejmě si coby autor svůj 13 let starý článek zkusím opravit, i když už jsem v PHP řadu let nic nedělal :) První řádek za složenou závorkou má být takto:

    $max = $pole[0]; for ($i = 0; $i $max) $max = $pole[$i];

    Od doby PHP 4.x je v jazyce přímo funkce max, v době psaní článku tam ještě nebyla.

Odpovědět