Základní kurz 6: Proměnné

Autor: Joker
Po menší (ovšem důležité) odbočce na téma chyb se nyní vraťme k tvorbě skriptů. Už v kapitole o základech syntaxe jsme si ukázali některé šikovné věci, které lze s PHP udělat, například jsme vytvořili společnou hlavičku pro stránky. Ale jedna nevýhoda je, že pořád umíme jen vypsat do stránky statický obsah, který je zadaný ve skriptu (sice jsme si povídali o jednoduchých výpočtech, ale například echo 2 + 3;, když čísla 2 a 3 jsou pevně daná v kódu, se co do praktického efektu moc neliší od echo "5";). Zatím neumíme výstup podle situace měnit. Zrovna třeba u společné hlavičky by bylo užitečné, kdyby titulek stránky nebyl napevno „Příklad z učebnice PHP“, ale nastavil se podle stránky, která hlavičku vkládá.

Místo pevné hodnoty bychom chtěli hodnotu, která se podle situace může měnit. A právě na takové proměnné hodnoty jsou v PHP (a jiných programovacích jazycích) proměnné.

Termín proměnná znáte z matematiky. Proměnné v programování nejsou úplně totéž, ale některé rysy jsou podobné. Základní charakteristiky proměnné v PHP jsou název a hodnota. Můžeme říci, že proměnná je úložiště, které má přiřazený nějaký název a obsahuje nějakou hodnotu.
Přiřazení hodnoty proměnné v PHP může vypadat třeba takto:

$promenna = "hodnota";

Podívejme se na jednotlivé charakteristiky proměnné blíže.

Název proměnné

Název proměnné v PHP vždy musí začínat znakem $ (dolar). Podle toho se pozná, co je proměnná. Na české klávesnici se znak dolaru napíše přes AltGr (pravý Alt) + ů, používáte-li českou QWERTY klávesnici, tak AltGr + č (česká QWERTY klávesnice při stisknutém AltGr téměř odpovídá anglické klávesnici, což psaní anglických symbolů a potažmo programování usnadňuje). Za dolarem následuje samotný název, který může obsahovat písmena, číslice a podtržítko, ale nesmí začínat číslicí.

Přestože použití například diakritiky nezpůsobí chybu, velmi se doporučuje používat jen písmena bez diakritiky.

Dejte také pozor, že přestože u příkazů na velikosti písmen nezáleží (echo a ECHO je to samé), u proměnných naopak záleží ($promenna a $Promenna jsou dvě různé).

Příklady názvů proměnných:

$pocet = 1; // správně
$Pocet = 1; // toto je jiná proměnná než ta předchozí
$počet = 1; // nezpůsobí chybu, ale použití diakritiky není vhodné
$4.slovo = "slovo"; // chyba, název nemůže obsahovat tečku ani začínat číslicí
$slovo4 = "slovo"; // správně
$pocet slov = 4; // chyba, název nemůže obsahovat mezeru
$pocetSlov = 4; // správně

Zvýrazňovač syntaxe a kontroly v IDE opět napoví, když nějaký název není syntakticky správný.

Doporučení, jak pojmenovávat proměnné

Hodnota proměnné


Proměnné můžeme nastavit hodnotu, nebo její hodnotu přečíst. Čtení hodnoty je snadné, stačí proměnnou použít ve výrazu tak, jako kdybyste chtěli použít tu hodnotu. K nastavení hodnoty slouží přiřazovací operátor (je jich více, ale zatím nám stačí operátor „rovná se“, =) a ukázali jsme si ho v prvním příkladu této kapitoly. První nastavení hodnoty určité proměnné se nazývá inicializace.

Opakem inicializace, který ale typicky nebudete potřebovat, je zrušení proměnné. To se provede příkazem unset()

<?php
$pozdrav = "Ahoj"; // inicializace proměnné
echo $pozdrav; // použití hodnoty proměnné
unset($pozdrav); // zničení proměnné
?>
Použití unset() je spíše výjimečné, určitě není nutné rušit všechny použité proměnné, PHP je zruší samo nejpozději po skončení skriptu.

Při pokusu o čtení z neexistující proměnné (takové, která nebyla ještě inicializovaná, nebo naopak byla zrušena), se stanou dvě věci: Generuje se chybové hlášení úrovně notice (tj. zpracování skriptu pokračuje dál) a jako hodnota proměnné se vrátí NULL, což je zvláštní hodnota označující, že proměnná neexistuje, resp. nemá žádnou hodnotu.

Přitom NULL neznamená řetězec "null", jde o zvláštní typ hodnoty, podobně jako jsme už v kapitole o základech syntaxe narazili na rozdíl mezi řetězcem a výrazem. Tím se dostáváme k důležité charakteristice hodnoty proměnné, kterou je datový typ. Ten udává v podstatě druh či „význam“ uložených dat. Některé operace je možné dělat jen některými datovými typy (například matematické operace lze dělat jen s čísly).

Někdy se mluví o datovém typu proměnné. V PHP se tím rozumí datový typ hodnoty proměnné. (V některých jiných programovacích jazycích se musí určit datový typ proměnné a hodnota proměnné je pak vždy daného typu. PHP funguje jinak, sama proměnná definovaný datový typ nemá a je určený čistě typem aktuálně uložené hodnoty.)

Datové typy


V PHP existují následující datové typy:

Podívejme se nyní blíže na první čtyři základní, tzv. skalární datové typy (skalární proto, že na rozdíl od složených obsahují pouze jednu dále nedělitelnou hodnotu).

String


Řetězce známe už z kapitoly o základech syntaxe. Víme, že řetězce lze uzavírat do uvozovek nebo do apostrofů ("řetězec", 'řetězec'), přičemž oba způsoby nejsou úplně rovnocenné, v řetězci v uvozovkách mají určité sekvence znaků speciální význam (viz také manuál).

Toto má velký význam u proměnných, protože řetězce v uvozovkách dělají tzv. expanzi proměnných: Když do řetězce v uvozovkách napíšete název proměnné, nahradí se hodnotou té proměnné. U řetězce v apostrofech se toto neděje (u řetězce v apostrofech jsou pouze dvě speciální konstrukce, \' a \\, jinak platí „co tam napíšete, to tam bude“).

Příklad:

<?php
$jazyk = "PHP";
$textUvozovky = "Programuji v $jazyk";
$textApostrofy = 'Programuji v $jazyk';

echo $textUvozovky; // vypíše: Programuji v PHP
echo $textApostrofy; // vypíše: Programuji v $jazyk
?>

Samotný znak $ se v řetězci v uvozovkách zapíše opět použitím zpětného lomítka, \$.

Komu expanze proměnných přijde matoucí, může místo toho psát proměnné mimo řetězec a řetězce skládat dohromady pomocí operátoru pro spojování řetězců, který se zapisuje tečkou.

<?php
$jazyk = "PHP";
// Použití operátoru pro spojování řetězců:
$veta = 'Programuji v ' . $jazyk . ', je to zajímavý jazyk';
echo $veta; // vypíše: Programuji v PHP, je to zajímavý jazyk
?>

Použití operátoru pro spojování řetězců je často přehlednější varianta.

Integer


S celými čísly jsme se také už setkali (u výrazů v kapitole o základech syntaxe). Zapisují se jednoduše číslicemi, záporná čísla s mínusem na začátku.
Kromě klasického všem známého zápisu čísel v desítkové soustavě PHP umožňuje čísla zadávat i v jiných soustavách: Nula před číslem znamená zápis v osmičkové soustavě, 0x nebo 0X před číslem zápis v šestnáctkové soustavě a od PHP 5.4 je přidán i zápis ve dvojkové soustavě, který se označuje 0b před číslem.

Příklad:

<?php
// Všechny následující zápisy vyjadřují číslo dvacet:
$a = 20;
$b = 0x14;
$c = 024;
$d = 0b10100; // Toto funguje až od PHP 5.4
?>

Záludný může být hlavně zápis v osmičkové soustavě, pokud byste se snažili číslo doplňovat nulami na určitý počet číslic. Například když uděláte $cena = 0500;, bude hodnota proměnné $cena (v desítkové soustavě) pouze 320!

Snažit se typ Integer doplňovat nulami kvůli formátování je chyba, protože tento datový typ slouží k matematickým operacím. Když chcete číslo nějak formátovat pro výpis, použijte řetězec. Je také hodně věcí, které v běžném životě nazýváme „číslo“, ale v programování jsou to (obvykle) řetězce, například: Telefonní číslo, rodné číslo, poštovní směrovací číslo, a podobně. Když něco chcete jen vypisovat a ne s tím provádět matematické operace, je to řetězec a ne číslo.

Kdybychom skutečně chtěli doplnit číslo nulami na určitý počet znaků, lze použít funkci str_pad(), která přebírá čtyři argumenty: Co se má doplnit, na jakou délku, čím a z jaké strany (výchozí hodnota je zprava).
Tedy například:

<?php
$cena = 500;
// doplnit na 4 znaky nulami zleva:
echo str_pad($cena, 4, "0", STR_PAD_LEFT); // 0500
?>

Datový typ integer nemůže pojmout jakékoli celé číslo, má určitý rozsah. Ten se může v různých systémech lišit, v PHP je předdefinovaná konstanta PHP_INT_MAX, která udává maximální možnou hodnotu datového typu integer, tzn.: echo PHP_INT_MAX; (bez uvozovek a bez $ na začátku) vypíše tuto hodnotu. Typická hodnota je trochu přes dvě miliardy. Nejmenší záporný integer je (-PHP_INT_MAX) - 1 (tzn. záporných integerů je o 1 víc než kladných).

Když se celé číslo do uvedeného rozsahu nevejde, nenastane žádná chyba, ale datový typ čísla se automaticky změní na float.

Float


Číslo v plovoucí řádové čárce, neboli desetinné číslo. Čísla se zapisují s desetinnou tečkou, tedy např. $pullitr = 0.5;

Lze také použít zápis známý třeba z fyziky, kdy se třeba 1 500 000 zapíše jako 1,5 x 10^6. Jen v PHP se místo „krát deset na“ napíše písmeno E (malé nebo velké):

<?php
$x = 1.5e6; // 1 500 000
// záporný exponent:
$x = 1.5e-3 // 0,0015
?>

Float má ohromný rozsah, který se opět může v různých systémech lišit, ale typické maximum je v řádu 10^308 (tedy o 299 řádů více než integer- ale háček je v přesnosti, viz níže).

Kromě „běžných” čísel obsahuje datový typ float ještě dvě, resp. tři speciální hodnoty: INF a NAN.
INF (infinity) znamená nekonečno, existuje kladné a záporné nekonečno (INF a -INF) a kromě výpočtů jejichž výsledkem i v matematice je nekonečno je také výsledkem výpočtů, při kterých dojde k přetečení (výsledná hodnota se nevejde do rozsahu datového typu float). Například funkce log() pro zadané číslo vrátí jeho logaritmus. A protože logaritmus nuly je -∞ (záporné nekonečno), výsledkem log(0) je -INF.
NAN (not a number) značí, že výsledek výpočtu není definovaný v oboru reálných čísel. Například funkce sqrt() vrátí odmocninu zadaného čísla. Protože odmocnina není (v oboru reálných čísel) definovaná pro záporná čísla, výsledkem například sqrt(-1) je NAN.

Poznámka: Pokud znáte JavaScript, možná víte, že tam nekonečnem (v JavaScriptu je to hodnota Infinity) končí i dělení nulou. V PHP to tak není, dělení nulou vyvolá varování (chybovou hlášku úrovně warning) a jeho výsledkem je logická hodnota false.

Přesnost reálných čísel


Reálných čísel je na každém intervalu (jehož hranice nejsou stejné číslo) nekonečně mnoho, zatímco datový typ float zjevně nemůže spotřebovat nekonečně mnoho paměti. Je tedy zřejmé, že musí mít omezenou přesnost. A tak to také je:
<?php
$pi = 3.14159265358979323846;
echo $pi; // 3.1415926535847
// Pozn.: Konkrétní výsledek může záviset na použité platformě
?>
(Mimochodem, číslo π nemusíte takhle do skriptu zapisovat, v PHP lze jeho hodnotu získat zavoláním funkce pi())

Do datového typu float je tedy možné uložit jen hodnotu z určitého pevně daného (byť ohromného) výčtu reálných čísel. Ostatní reálná čísla se musejí zaokrouhlit na nejbližší uložitelnou hodnotu.
Zde nastává další komplikace: Počítače čísla interně neukládají v desítkové soustavě, se kterou běžně pracujeme my, ale ve dvojkové. Přitom že nějaké číslo má krátký rozvoj v desítkové soustavě (málo desetinných míst) neznamená, že to tak je i ve dvojkové, například dvojkový rozvoj čísla 0.1 je nekonečně dlouhý.

Zaokrouhlení se proto nemusí týkat jen nepodstatných řádů a může postihnout i čísla, u kterých bychom to se zkušenostmi z desítkové soustavy neočekávali. Ukážeme si příklad, kde použijeme funkci floor(), která vrací celou část čísla (neboli „zaokrouhlí dolů“). Při té příležitosti ještě zmiňme funkce ceil(), která naopak vrátí nejbližší vyšší celé číslo, a round(), která dělá běžné zaokrouhlení známé z matematiky (resp. způsob zaokrouhlení lze ovlivnit jejími parametry, viz odkaz do manuálu).

<?php
$vysledek = (0.1 + 0.7) * 10;
echo $vysledek; // vypíše 8
echo "<br>";
echo floor(8); // vypíše 8
echo "<br>";
echo floor($vysledek); // vypíše 7
?>

Výpis přes echo sice vypíše 8, ale interní reprezentace výsledku daného výpočtu v paměti je 7.9999999999999991118…, proto výsledkem volání floor() není 8, ale 7.

S tím je třeba počítat, zejména je riskantní různými výpočty získat dvě reálná čísla a pak kontrolovat, jestli se sobě rovnají (například výsledek výše uvedeného výpočtu (0.1 + 0.7) * 10 se nebude rovnat číslu 8.0).

Přesnost typu float není daná na určitý počet desetinných míst, ale na určitý počet řádů. To znamená, že čím vyšší číslo je v něm uloženo, tím vyššího řádu je i zaokrouhlovací chyba. V běžné instalaci PHP by měla přesnost být na 14 řádů (tzn. číslo v řádu jednotek bude přesné na 13 desetinných míst, číslo v řádu stovek bilionů bude přesné do řádu jednotek).

Boolean


Logický typ má dvě možné hodnoty, true a false. Hodnota true se používá ve významu „ano“, „je splněno“, hodnota false ve významu „ne“, „není splněno“. Význam tohoto datového typu si ukážeme v pozdějších kapitolách.

Vypsání hodnoty a typu proměnné


Hlavně při vývoji se někdy stane, že bychom chtěli ověřit, jakou hodnotu jakého typu proměnná v určitou chvíli obsahuje. K tomu slouží funkce var_dump(). Funkci lze předat proměnnou a na výstup se vypíše datový typ a hodnota.
Příklad:
<?php
$pozdrav = "Ahoj!";
var_dump($pozdrav);
?>
Vypíše: string(5) "Ahoj!", „string“ je datový typ, u řetězce je v závorce jeho velikost v bajtech a pak následuje výpis hodnoty, u ostatních skalárních typů je v závorce rovnou hodnota.
Použití var_dump() na neexistující proměnnou generuje poznámku (notice) o nedefinované proměnné a vypíše „NULL“.

Ještě jedna poznámka k řetězcům, všimněte si, že ve vícebajtových kódováních jako je UTF-8 nemusí velikost řetězce v bajtech (tedy číslo ve var_dump) odpovídat délce řetězce ve znacích.
Příklad:

<?php
$pozdrav = "Čau";
var_dump($pozdrav); // string(4) "Čau", „Č“ jsou v UTF-8 dva bajty
?>

Ukázka použití proměnných


Proměnné jsou důležitou součástí téměř všech programovacích jazyků, v PHP i v dalších kapitolách tohoto kurzu se s nimi budete setkávat každou chvíli. Pro začátek si ukážeme jednoduchý příklad použití.
Na začátku jsme zmínili, že by v naší společné HTML hlavičce bylo dobré místo pevného titulku mít titulek podle stránky, kam se hlavička vkládá. Pusťme se do toho.

Uděláme si stránku, která společnou hlavičku vkládá, tam budeme muset zadat titulek.

<?php
$titulek = "Příklad titulku stránky";
include "spolecha_hlavicka.php";
?>
<body>Zde bude obsah stránky</body>

Jak jsme si už vysvětlili, vkládaný soubor se vloží na místo, kde je příkaz include (případně require). Pokud vkládaný soubor je PHP skript, budou v něm dostupné proměnné, které jsou dostupné v hlavním skriptu na místě příkazu include. Proto musíme hodnotu proměnné $titulek zadat ještě před příkazem include.

A nyní nový soubor spolecna_hlavicka.php:

<?php mb_internal_encoding("UTF-8"); ?>
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title><?php echo $titulek; ?></title>
</head>
(Zvýrazněné jsou změny proti předchozímu kódu.)

Přes proměnnou $titulek lze nyní titulek stránky zadat pro každou stránku zvlášť. Uvedený kód má ale jednu vadu: Hlavička spoléhá, že proměnnou $titulek definuje nadřízený skript. Když to nadřízený skript neudělá, titulek bude prázdný a bude se generovat chybové hlášení o použití nedefinované proměnné. I když skript pak bude pokračovat dál a žádný další problém to nezpůsobí, bylo by dobré umět zjistit, jestli proměnná existuje, případně také nastavit nějakou výchozí hodnotu.

Kontrola existence proměnné


Ke zjištění, jestli proměnná existuje a případně jestli je prázdná, slouží dva příkazy: isset() a empty().
U těchto dvou příkazů předání neexistující proměnné nevyvolá chybové hlášení. (Protože to nejsou funkce, ale příkazy integrované v samotném PHP; Jakkoliv se vestavěné funkce a příkazy od sebe někdy těžko poznají. V anglickém manuálu u příkazů obvykle najdete poznámku, že jde o „language construct and not a function“).

Jak isset(), tak empty() vracejí hodnotu typu boolean. Příkaz isset() vrátí true v případě, že proměnná byla inicializovaná a nebyla dosud zrušená, jinak řečeno není NULL. V opačném případě vrátí false. Příkaz empty() má obrácenou logiku, vrátí true když je proměnná „prázdná“ a false když není. Zároveň ale „prázdná“ proměnná neznamená jen NULL, ale i některé další hodnoty. Za „prázdnou“ se považuje i taková proměnná, jejíž hodnota je prázdný řetězec (""), číslo 0 (případně 0.0), řetězec "0", logická hodnota false nebo prázdné pole (o polích si řekneme později).

Každý z příkazů se tedy hodí pro trochu odlišné situace. V našem případě nám půjde jen o to, zda stránka proměnnou $titulek nastavila, tedy použijeme isset(). Abychom uměli vyjádřit „pokud byla proměnná nastavena“, budeme potřebovat podmínky, o kterých jsme ještě nemluvili. Proto si teď jen ukážeme jejich syntaxi a blíže si je vysvětlíme později.

Nový soubor spolecna_hlavicka.php:

<?php
    mb_internal_encoding("UTF-8");
    $title = "Příklad z učebnice PHP"; // Zavedeme si novou proměnnou

    if (isset($titulek)) { // Jestliže existuje $titulek
        $title = $titulek; // nastavíme $title na stejnou hodnotu
    } // konec podmínky
    // Když neexistuje $titulek, v $title zůstane původní hodnota
?>
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title><?php echo $title; ?></title>
</head>

Nyní se titulek nastaví pouze když stránka, kde se hlavička vkládá, nastaví nejdříve proměnnou $titulek.

Vyzkoušejte si

1. Vytvořte si skript s definicí a výpisem nějaké proměnné (analogický k příkladům na var_dump). Zkuste do proměnné dávat různé hodnoty různých typů a vždy skript znovu otevřít v prohlížeči a pozorovat, co se vypíše.

2. Založte skript, ve kterém vytvoříte proměnnou $test, jejíž hodnotou bude řetězec "0". Na tuto proměnnou použijte příkaz empty() a jeho výsledek uložte do proměnné $prazdna. Pomocí var_dump vypište, co je v proměnné $prazdna.

3. Do skriptu z předchozího bodu ještě podobně, jako se ukládá výsledek empty() do $prazdna, přidejte uložení výsledku isset() do proměnné $existuje a výpis této proměnné.

4. U skriptu z předchozího bodu před každý var_dump vypište (pomocí echo) název vypisované proměnné, tedy „$prazdna“ a „$existuje“. Zařiďte, aby se skutečně vypsal název proměnné, včetně znaku dolaru.

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í