Základní kurz 7: Přetypování

Autor: Joker
V předchozí kapitole jsme se seznámili s proměnnými a datovými typy. V této kapitole si ukážeme, jak lze hodnoty převádět na jiné datové typy. V některých situacích se hodnoty mohou přetypovat automaticky aniž by si to programátor vyžádal nějakým zvláštním příkazem, je tedy potřeba znát, za jaké situace a podle jakých pravidel se hodnoty přetypují.

Vynucené přetypování

Ukažme si nejdříve přetypování vynucené programátorem, které je vcelku přímočaré. Prostě se to, na co chceme přetypovat, napíše do závorky před hodnotu nebo proměnnou, kterou chceme přetypovat.

Možnosti přetypování jsou tyto:

Ukázka přetypování:

<?php
$cislo = 1; // číslo
$retezec = (string) 1; // číslo přetypované na řetězec
 // Necháme si vypsat hodnoty proměnných:
echo 'hodnota $cislo: ';
var_dump($cislo);
echo 'hodnota $retezec: ';
var_dump($retezec);
?>

Vypíše, že hodnota $cislo je 1 typu int (celé číslo) a hodnota $retezec je '1' typu string (řetězec).

Přetypování proměnné jen vrátí hodnotu nového datového typu, ale nezmění samotnou proměnnou. Chcete-li na nový datový typ změnit hodnotu proměnné, musíte pak výsledek přiřadit zpátky do té proměnné.

<?php
$cislo = 1; // číslo
$retezec = (string) $cislo; // $retezec bude řetězec "1", ale $cislo bude pořád číslo
$cislo = (float)$cislo; // Takto se změní datový typ samotné proměnné

Jak se co přetypuje?

Možná vás teď napadlo, že ne všechna přetypování mají intuitivní výsledek, například:

$hodnota = (int)"Ahoj!";

Pravidla přetypování jsou tato:

Přetypování na řetězec (string):

Číslo se jednoduše převede na odpovídající řetězec (třeba 15 na "15"). Dejte jen pozor, že u reálných čísel nemusí být výsledekem číslo "hezky formátované". Jednak desetinná tečka versus čárka a jednak velmi vysoká nebo velmi malá čísla jsou zapsána v tzv. exponenciálním tvaru, který jsme zmínili v předchozí kapitole. Například (string)100000000000000 vrátí řetězec "1.0E14", nebo (string)0.000036 vrátí řetězec "3.6E-5".

Přetypování na celé číslo (int):

Z reálného čísla se bere celá část (takže se nezaokrouhluje), například 17.9 se převede na 17. Při konverzi výsledku nějakého výpočtu ale nezapomeňte na specifika ukládání reálných čísel, jak je zmíněno v minulé kapitole. Výsledek výpočtu s reálnými čísly bude v paměti uložen jako nejbližší uložitelné reálné číslo, které se tedy může nepatrně lišit od skutečného výsledku. To ale znamená, že přesně celočíselný výsledek výpočtu může být uložený jako nepatrně nižší reálné číslo. A jelikož převod na celé číslo bere celou část, může pak výsledkem být číslo o 1 nižší.

Příklad:

<?php
$vysledek = (0.7 + 0.1) * 10;
var_dump($vysledek); // $vysledek je 8 typu float
$vysledek = (int)$vysledek; // přetypujeme na celé číslo
var_dump($vysledek); // $vysledek není 8, ale 7 typu int
?>

Naopak logické hodnoty jsou nezáludné, true se převede na 1 a false na 0. U řetězce se jde od jeho začátku tak dlouho, dokud ho lze interpretovat jako číslo a případný zbytek řetězce se ignoruje.
Pokud začátek řetězce vůbec nejde převést na číslo (nebo je řetězec prázdný), je výsledkem 0. Například (int)"-15" je -15, (int)"10Kč" je 10, (int)"Vlak s 10 vagóny" je 0. Rozpozná i výše zmíněný exponenciální tvar, tedy např. "1.2e3" se převede na 1200.

Přetypování na reálné číslo (real/double/float)

Analogické k přetypování na celé číslo, jen nehrozí zmíněný problém s celou částí čísla.

Přetypování na logickou hodnotu (bool)

Pokud jde o číslo, převede se 0 na false, cokoli jiného na true. V případě řetězce se prázdný řetězec převede na false, všechno ostatní na true. Pozor, znamená to, že i řetězec "false" se převede na true! Neosvojujte si proto zvyk některých začátečníků psát uvozovky kolem všech hodnot, nejen řetězců.

Krátká poznámka k polím a objektům

Jak už je napsáno výše, polím se bude věnovat pozdější kapitola a objektům až další část tohoto webu po skončení základního kurzu. Když je ale řeč o přetypování, pro úplnost zmiňme, že přetypování polí či objektů na jiné typy, ani přetypování jiných datových typů na pole či objekty obvykle nedává valný smysl.

Pokus o přetypování objektu na jiný datový typ dokonce může skončit chybovou hláškou.

Skryté (automatické) přetypování

Kromě přetypování vynuceného programátorem jsou v PHP i situace, kdy se datový typ hodnoty změní automaticky důsledkem nějakého výpočtu.

I když to není úplně přetypování o jakém jsme mluvili doteď, připomeňme si z minula, že proměnné nemají pevně stanovený datový typ, ale jen datový typ v nich uložené hodnoty. Ten se samozřejmě může změnit přiřazením jiné hodnoty.

<?php
$promenna = 1; // $promenna je typu integer (celé číslo)
$promenna = "ahoj"; // $promenna je nyní typu string (řetězec)
?>

Z předchozí kapitoly o datových typech dále víte, že celé číslo, které je příliš vysoké (nebo příliš nízké záporné), než aby šlo uložit do typu integer, se automaticky převede na typ float (a pokud se nevejde ani do jeho rozsahu, změní se na speciální hodnotu INF, reprezentující nekonečno).

Příklad:

<?php
var_dump(99*99);
var_dump(9999999999*9999999999);
?>

Zatímco výsledkem prvního výpočtu bude normálně 9801 typu int, výsledkem druhého výpočtu je 9.999999998E+19 typu float, což znamená 9.999999998 * 10^19, neboli 99999999980000000000. Všimněte si, že ve skutečnosti má výsledek toho součinu být 99999999980000000001. Opět jde o nepřesnost kvůli způsobu uložení reálných čísel, o které jsme už mluvili. Zároveň vidíme názornou ukázku toho, jak vyšší řád čísla znamená i vyšší řád nepřesnosti.

To může vést k paradoxním situacím:

<?php
$soucin = 99999999980000000000;
$soucet = $soucin + 100;
var_dump($soucin);
var_dump($soucet)
?>
Všimněte si, že ačkoli proměnná $soucet vznikla přičtením 100 k proměnné $soucin, obsahují obě proměnné stejné číslo! A to dokonce přesto, že ve skriptu máme pouze celá čísla. Je to způsobené mechanismem popsaným výše, tedy příliš vysoké celé číslo se automaticky převedlo na reálné. Protože řád prvního čísla je 10^19, jakékoli změny menšího řádu než 10^4 (tedy desetitisíce) nemusejí dávat přesné výsledky.

Také operandy ve výrazech se automaticky přetypují na datový typ, který je vyžadován použitým operátorem. Operátorům a jimi očekávaným datovým typům se budeme blíže věnovat v příští kapitole.

<?php
$vysledek = "10" + "1"; // $vysledek bude 11
?>
V příkladu výše je použit operátor sčítání (+), který očekává čísla, ale operandy jsou řetězece. Proto se převedou na čísla, aby bylo možné spočítat výsledek. Zároveň si zapamatujte, že operátorem + nejdou v PHP "sčítat", tedy spojovat, řetězce (jak ukazuje i příklad výše). U proměnných opět platí, že se přetypuje pouze hodnota použitá ve výrazu, ale ne hodnota samotné proměnné:
<?php
$vstup = "5";
$vysledek = $vstup + 1;
// $vysledek je číslo (integer) 6, v $vstup zůstane řetězec "5"
?>

Také příkazy jako echo, pokud dostanou hodnotu jiného datového typu než očekávají, ji přetypují.

Příklad:

<?php
$logicka = true;
echo $logicka;
?>

Vypíše 1, protože echo očekává řetězec a logická hodnota se přetypuje na řetězec "1". Když v příkladu použijete false místo true, nevypíše se nic (false se převádí na prázdný řetězec, vzpomínáte?)

Jiné techniky převodu datových typů

Poměrně často se stává, že potřebujete změnit datový typ, ale podle jiných pravidel, než těch výše uvedených. Například potřebujete převádět mezi logickou hodnotou a řetězcem tak, aby hodnota true odpovídala řetězci "ano" a hodnota false řetězci "ne". Tato situace je možná častější, než použití standardního přetypování. Takovéto podmínky je ovšem potřeba odprogramovat přímo v kódu.

Některá možná řešení si ukážeme v následujících kapitolách.

Shrnutí

Datový typ hodnoty může změnit sám programátor příkazem pro přetypování, nebo se datový typ může změnit automaticky během výpočtu, pokud operátor nebo příkaz vyžaduje jiný datový typ, než hodnota má. Také funkce většinou u svých argumentů počítají s nějakým datovým typem, ačkoliv se při definici argumentů datový typ nespecifikuje (PHP ostatně ani u proměnných nemá pevné datové typy). Při práci s argumentem uvnitř funkce se hodnota obvykle přetypuje. Některé funkce si typ argumentů kontrolují a je-li předaná hodnota špatného typu (nebo nejde přetypovat na ten správný), mohou vyhodit chybovou hlášku.

Jak již víme z předchozí kapitoly, celá čísla vyšší než dokáže pojmout datový typ integer se automaticky přetypují na reálná čísla (float), která trpí určitou nepřesností vlivem způsobu uložení reálných čísel v paměti. Přitom tato nepřesnost roste s hodnotou uloženého čísla, takže je dobré na to dát pozor, pokud byste například sčítali velmi vysoká čísla s velmi nízkými.

Často je potřeba převést datové typy mezi sebou podle jiných pravidel, než standardní PHP přetypování. Toto je nutné odprogramovat ve skriptu a některé příklady si ukážeme později v tomto seriálu.

Vyzkoušejte si

Zkuste si, jaké výsledky dají různá přetypování. Zamyslete se, proč to tak je. Například:

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í