Základní kurz 14: Rozsah platnosti proměnných

Autor: Joker
Když byla řeč o komunikaci funkce s okolním kódem, zmínili jsme, že ve funkci nelze jednoduše používat proměnné definované okolním kódem. Může za to věc, které se říká kontext (v angličtině scope). Z hlediska proměnných každá funkce má svůj kontext (v případě objektů metoda a ještě existuje kontext samotného objektu). Kromě toho existuje ještě hlavní kontext samotného skriptu.
<?php
function mojeFunkce() {
  // zde je kontext funkce mojeFunkce

  $kontext = "Kontext mojeFunkce";
  echo "<p>$kontext</p>";
}

function druhaFunkce() {
  // zde je kontext funkce druhaFunkce

  $kontext = "Kontext druhaFunkce";
  echo "<p>$kontext</p>";
  mojeFunkce(); // přechod do jiného kontextu
  echo "<p>$kontext</p>"; // opět v kontextu druhaFunkce
}

// hlavní skript
$kontext = "Kontext skriptu";
echo "<p>$kontext</p>";
druhaFunkce(); // přechod do jiného kontextu
echo "<p>$kontext</p>"; // opět v kontextu hlavního skriptu
?>

Lokální a globální proměnné


Proměnné definované a používané v kontextu funkce, jak bylo zatím popsáno, se nazývají lokální proměnné. Druhý druh jsou globální proměnné, což jsou proměnné definované na úrovni celého skriptu (v hlavním kontextu). Tyto proměnné lze zpřístupnit i v podřízených kontextech.

Kontext hodlající použít globální proměnné musí nejdřív označit, které proměnné chce jako globální používat. K tomu slouží klíčové slovo global. Proměnná označená jako globální se pak chová, jako bychom byli stále v globálním kontextu.

Přepišme si příklad výše s použitím globálních proměnných:

<?php
function mojeFunkce() {
  global $kontext; // nastavíme $kontext jako globální proměnnou

  $kontext = "Kontext mojeFunkce";
  echo "<p>$kontext</p>";
}

function druhaFunkce() {
  global $kontext; // nastavíme $kontext jako globální proměnnou

  $kontext = "Kontext druhaFunkce";
  echo "<p>$kontext</p>";
  mojeFunkce(); // přechod do jiného kontextu
  echo "<p>$kontext</p>"; // opět v kontextu druhaFunkce
}

// hlavní skript
$kontext = "Kontext skriptu";
echo "<p>$kontext</p>";
druhaFunkce(); // přechod do jiného kontextu
echo "<p>$kontext</p>"; // opět v kontextu hlavního skriptu
?>

Vyzkoušejte oba příklady a všimněte si rozdílu v chování: U příkladu na začátku kapitoly, i když se proměnná jmenuje všude $kontext, je to uvnitř každé funkce jiná proměnná. Pokud ji ale používáme jako globální, je to v rámci celého skriptu pořád jedna proměnná.

Proč nepoužívat globální proměnné


Možná si teď říkáte, proč vlastně v této kapitole a v kapitole o funkcích nebylo rovnou řečeno, že si lze předávání dat do funkce a z funkce zjednodušit použitím globálních proměnných. Důvod je ten, že to většinou není dobrý nápad.

Hlavní kámen úrazu globálních proměnných je právě to, že jsou globální. Ve složitějších skriptech je těžké dohlédnout, kde všude se globální proměnná používá a kde a kdy se může změnit. To pak často vede k problému zvanému „action at a distance”, do češtiny to lze přeložit jako „vzdálené působení”, kdy změna jednoho místa programu má nečekané dopady v úplně jiné části programu.

Zároveň jeden z hlavních přínosů funkcí je, že můžete řešení jednoho konkrétního problému oddělit a pak ho používat opakovaně na různých místech. Globální proměnné naopak funkci svazují s okolním prostředím a její použití jinde znesnadňují. Funkce by v ideálním případě měla být uzavřená entita nezávislá na okolním prostředí (v objektově-orientovaném programování je taková uzavřená entita objekt).

Například u různých nastavení aplikace se může stát, že chcete proměnnou, která se na jednou nějak nastaví a pak by k ní byl globální přístup pro čtení. To ovšem není globální proměnná, ale konstanta.
Místo například:

<?php
    $pocet = 5; // $pocet simuluje nějaké globální nastavení v aplikaci

    function vypisPocet() {
    // Pozn.: Toto je jen pro ukázku.
    // Reálně by takováto funkce neměla smysl
        global $pocet;

        echo $pocet;
    }
?>
by lepší řešení bylo:
<?php
    define("POCET", 5);

    function vypisPocet() {
        echo POCET;
    }
?>

Superglobální proměnné


V kapitole o předávání dat jsme si ukázali, že data odeslaná návštěvníkem z formuláře se ukládají do speciálních proměnných, polí $_GET, $_POST a $_REQUEST. Když budete experimentovat s jejich použitím uvnitř funkcí, zjistíte, že se nechovají podle toho, co jsme si zatím řekli. Respektive že je můžete používat v jakémkoliv kontextu i když je neoznačíte jako globální. To proto, že $_GET, $_POST a $_REQUEST patří mezi speciální, takzvané
superglobální proměnné. Jde o sadu předem definovaných proměnných v PHP (takže si nemůžete sami definovat novou superglobální proměnnou), z nichž každá obsahuje nějaký specifický druh dat.

Všechny superglobální proměnné v PHP jsou typu pole. S $_GET, $_POST a $_REQUEST jsme se v rámci tohoto kurzu už setkali, ale existují i další. I když použití všech z nich nebudeme teď do detailu rozebírat, můžete následující seznam používat i později jako referenci, kde jaký typ dat hledat.

Popis superglobálních proměnných najdete také v manuálu PHP.

Existence superglobálních proměnných a fakt, že jsou to pole, by mohla vést k nápadu je zneužívat jako jakési globální úložiště dat. To je ovšem špatný nápad, který může vnést do skriptu bezpečnostní díry a vytvořit extrémně matoucí kód.

Všechny superglobální proměnné s výjimkou $_SESSION a případně $GLOBALS používejte jen pro čtení, tzn. skript by je neměl nijak měnit. Pokud potřebujete s nějakou hodnotou dál pracovat, zkopírujte si ji do lokální proměnné. Když potřebujete např. zapsat novou cookie, použijte funkci setcookie a ne vložení položky do $_COOKIE (to nefunguje).

Vyzkoušejte si


  1. Zkuste vytvořit funkci využívající globální proměnnou. Pak zkuste funkci upravit tak, aby místo globální proměnné využívala argument(y).
  2. Nechte si vypsat hodnoty superglobálních proměnných $_SERVER a $_ENV.
  3. Zopakujte si fungování superglobálních proměnných $_GET, $_POST a $_REQUEST, zkuste vytvořit formulář odesílající data a skript na jejich zpracování. V případě nejasností konzultujte s kapitolou o předávání dat na server.

Máte návrh na vylepšení či doplnění článku? Obsahuje článek nepřesné informace, nebo v něm chybí něco důležitého?
Tento článek má diskusní vlákno na diskusi Jak Psát Web, kam můžete náměty a připomínky napsat.


Správcem webu Péhápko.cz je Joker, mail zavináč it-joker tečka cz. Informace o autorských právech a možnostech použití obsahu viz Autorská práva
Přihlášení