Nedávno psal Jakub Vrána o tom, jak zjistit
příslušnost prvku v seznamu. Zmínil se také o variantě Switch &
Case, kterou lze nahradit sérii podmínek if
.
switch ($a) {
case 'a':
case 'b':
case 'c':
case 'd':
default:
}
Tato konstrukce může být v určitých jazycích a za určitých situací nesmírně rychlá. Bohužel v PHP tomu tak není. V časově kritických rutinách se jí raději vyhněte (tedy této konstrukci, případně PHP vůbec).
Pro rekapitulaci, zjistit příslušnost prvku lze nejméně pěti způsoby:
If série
Nejpomalejší metoda, vhodná tehdy, pokud se „formát“ podmínky
případ od případu liší (pokud se neopakuje jen $ch==...
). Viz
demo č. 1.
if ($ch=="\x00") { /* ... */ continue; }
if ($ch=="\x01") { /* ... */ continue; }
...
Switch & Case
Rychlejší a přehlednější varianta. Viz demo č. 2.
switch ($ch) {
case "\x00": /* ... */ break;
case "\x01": /* ... */ break;
...
}
in_array
Připravíme si pole hodnot a pak už jen testujeme (ne)přítomnost prvku v tomto poli. Viz demo č. 3.
if (in_array($ch, $arr)) {
// ...
} else {
// ...
}
array_key_exists
Opět pracuje nad polem, tentokrát se však netestuje přítomnost hodnot, alébrž klíčů (indexů). To je obecně velmi rychlé a tato metoda patří mezi nejrychlejší. Viz demo č. 4.
if (array_key_exists($ch, $arr)) {
// ...
} else {
// ...
}
isset
Zoptimalizovaná předchozí varianta. Využívá se jazykové konstrukce
isset
. Ta je rychlejší než funkce array_key_exists
,
narozdíl od ní však nedokáže zjistit přítomnost klíče null v poli. Viz
demo č. 5.
if (isset($arr[$ch])) {
// ...
} else {
// ...
}
Srovnání
Rychlostní srovnání hovoří myslím jasně (větší hodnota znamená delší dobu zpracování).
Optimalizovat kód pro isset
je obvykle velmi výhodné.
A netýká se to jen polí, lze kupříkladu testovat i délku řetězce
(isset($str{14})
namísto strlen($str)>14
) atd. Ale
to už hraničí s horší čitelností kódu.
Komentáře
Arthur Dent #1
Až když jsem to zkopíroval do tohodle okýnka (chtěl jsem ti napsat, že tam máš chybu), tak jsem si všiml, že v tom textu „isset($str{14})“ jsou ty závorky okolo čtrnáctky složené… Už je to se mnou vážný… Možná bys mohl udělat nějaké výraznější rozlišení mezi {} a () i v textu příspěvku, co ty na to? :)
(embedded IE6 / Feedreader, WinXP)
Dero #2
Díky, další článek – další pro mne zajímavá informace. Mám rád ty chvíle, kdy mi v čtečce svítí nepřečtená La Trine. :o)
Andrew #3
Zdá se mi to nebo tu někdo srovnává jablka, hrušky a švestky k tomu?
Srovnání if a switch beru. Stejně tak in_array a isset. Ale nějak nedokážu pochopit proč je to všechno v jednom grafu a ještě s funkcí array_key_exists, vždyť se ty funkce používají k naprosto jiným věcem.
Nebo mi snad někdo dokáže vysvětlit, jak to „pomalé switch a case“ nahradím tím ultrarychlým isset? Jinak navrhuju přidat do grafu třeba unset, mysql_connect, imacreatetruecolor a ještě pár dalších, ať to máme kompletní.
Jan Menšík #4
Prestoze funkce issset ci in_array samozrejme nedosahuji moznosti IF nebo SWITCH, ale chapu ze nekdy jdou pouzit a jsou rychlejsi.
Domnivam se ale ze lepsi je misto silenych konstruktu psat hezky citelny kod. Lepe se s nim pracuje a tim padem se i lepe ladi. A treba zjistite ze danou testovanou podminku vubec nepotrebujete.
Problem s rychlosti se vetsinou vyresi cacheovanim.
David Grudl #5
#3 Andrewe, je to reakce na odkazovaný článek, kde se tyto funkce vzájemně nahradit dají.
Ale kdybych to vzal obecně, lze použít třeba toto nahrazení:
za
Tedy jednotlivé volby
case
jsem nahradil funkcemi a ty jsou volány „přímo“, nikoliv po otestování neměnné sériecase
. Při zpracování velkého řetězce lze očekávat dramatické zrychlení, jak naznačuje graf. Ten koneckonců slouží pouze pro vizuální představu, konkrétní hodnoty v něm neuvádím, protože by to bylo zavádějící.#4 Jane Menšíku, Na cacheování ne nespoléhejte, není všemocné. Kód sice urychlí, ale poměr rychlostí různých metod zůstane ± zachován.
Souhlasím, že psát hezký a čitelný kód je potřeba (viz poslední věta článku), nicméně použití „rychlejší“ konstrukce přece neznamená psát nečitelněji.
johno #6
DGX: Zaujimalo by ma kolko krat si testy spustil a ci si to nejako potom spriemeroval. Taktiez standardnu odchylku by som si rad pozrel. Ak je totiz standardna odchylka priliz velka tak je ten graf minimalne zavadzajuci.
David Grudl #7
#6 johno, spustil jednou, zaokrouhlil na sekundy. Johno, nepíšu diplomovou práci – pokud máš zájem, zdrojáky jsou k dispozici a můžeš tomu věnovat hromadu času, provést hloubkové analýzy a nejspíš přijdeš na to stejné.
johno #8
#7 Davide Grudle, Robit nejake zavery na zaklade jedneho spustenia mi prijde minimalne ako primitivne.
David Grudl #9
#8 johno, a když se jeden skript vykonává např. 30 sekund a druhý necelé dvě? Navíc v případě PHP4 mívám odchylky docela minimální (5%), pravda, u PHP5 to umí udělat i 20%.
johno #10
#9 Davide Grudle, No prave taketo veci sa velmi lahko odhaluju, ked vidis standardnu odchylku. Ak je mala, tak to znamena, ze testy prebiehali stabilne bez nejakeho velkeho vonkajsieho vplyvu. Samotny priemer to nie je to prave orechove.
Predstav si situaciu, ze pustas test 3×. Dva krat zbehne za 3 sekundy a raz za minutu. Prehanam, ale vyratajme si priemer.
priemer = (3+3+60)/3 = 22sekund
standardna odchylka = 26.87
Hmm, nieco sa nam tu asi posralo.
Zoberme teraz priklad pri testoch s casmi 2, 3, 3 sekund.
priemer = 2.66
odchylka = 0.47
Toto uz vyzera na doveryhodnejsie (stabilnejsie) vysledky.
Je mi jasne, ze ked je tam radovy rozdiel, tak standardna ochylka bude asi zbytocna, ale v tych ostatnych pripadoch by nemala chybat.
David Grudl #11
Johno, máš zcela pravdu a tvůj komentář by si měl přečíst každý, kdo hodlá provádět nějaké měření.
Samozřejmě, že jsem měřil poctivě, samotného mě výsledky zajímaly. Ale v reakci #7 David Grudl jsem Tě prostě odbyl, protože jsi po mě chtěl práci navíc (tedy měřit znovu, neboť odchylku ‚neskladuju‘), ačkoliv si ji můžeš udělat sám (zdrojáky jsou k dispozici).
Marty #12
Benchmarky jsou jinde? Resp. odkazy na ně nefungují.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.