Ternární operátor osobně využívám docela často, proto mě nedávno překvapil příspěvek na blogu Fabiena Potenciera, který se zmiňuje o tom, že ternární operátor může být za určitých okolností až 1000x i více pomalejší než použití konstruktu if.
Problém je v tom, že chování ternárního operátoru je interně v PHP representováno tak, že vždy vrací kopii operandu a nepoužívá tedy mechanizmus copy on write, který je běžný např. pro obyčejný operátor přiřazení.
//huge array for ($i = 0; $i < 100000; $i++) { $content['test'][$i] = $i; } //very slow $test = isset($content['test']) ? $content['test'] : ''; //fast if (isset($content['test']) { $test = $content['test']; } else { $test = ''; } //huge string $content = file_get_contents('http://www.w3.org/TR/2011/WD-html-markup-20110525/spec.html'); //very slow $test = $content !== false ? $content : ''; //fast if ($content !== false) { $test = $content; } else { $test = ''; }
Určitě bych se v důsledku tohoto nevzdával ternárního operátoru, který využívám zejména proto, protože je to výraz jehož výsledkem je hodnota. Většina porovnávání ternárního operátoru bývá na malinkých datech, ale určitě je dobré o tomhle nepěkném chování vědět. V internals se podle komentářů na originálním článku už o tom ví. Zatím to nevypadá, že by to bylo opraveno, tak snad časem na to budeme moci zapomenout.
Pozn: Na stejný problém upozornil již před pár lety D. Grudl. Jen doplním, že já se k aktuálnímu chování stavím jednoznačně negativně i vzhledem k tomu, že se to přeneslo z verze 4 do verze 5.
Komentáře (8)
ale to je přeci pět let známá věc :]
http://latrine.dgx.cz/php-puvab-optimalizace-rychlosti
ale díky za připomenutí
No ano, sranda je, že to asi lidi moc nepálí, jinak si nedovedu vysvětlit, že to tak dlouhou dobu nikdo neopravil.
[2] Podle me je to tim, ze 99% ternarnich operatoru se pouziva s funkcema is_null(), empty(), isset() apod, ktere vraci bool, takze ten ternarni operator kopiruje nanejvejs ten bool a ten je minimalistickej.
[3] Já myslim že problém neni v části před otazníkem, ale v tom, za nim, schválně si přečti ten článek od Davida uvedený výše...
Pochopil jsem to tak, že se vyhodnotí výraz a neprovede se klasický přiřazení stylem reference countingu, ale rovnou přiřazení(kopírování) hodnoty čož v případe velkého textu chvíli zabere...
Osobně v tom ale problém nevidim, protože ve chvíli kdy použiju ternární operátor tak stejně v případě kdy s tou proměnnou mám vplánu dál pracovat, takže ke kopírování hodnoty stejně dojde, byť později...
[3] ne, výraz před otazníkem v ternárním operátoru s tímto chováním opravdu nemá nic společného
[4] neřekl bych, zrovna u velkých řetězců to může být problém, je běžné, že nějaký velikánský řetězec načtu a pak ho jen zpracovávám ale už ho neměním a pokud použiji ternární operátor výše popsaným způsobem jsem v pytli. U polí to asi bude menší problém, ty se modifikují spíše.
Ať jsem se snažil, jak jsem se snažil, nepovedlo se mi udělat nějaký zásadní výkonnostní rozdíl. Co dělám špatně?
https://gist.github.com/1151069
[6] no to je mi teda bashophpmaso, pustil jsem si to a nechal si vypsat ten kód, co je vykonáván a přijde mi, že testujete ternární operátor pokaždé zhruba takto :
jestli je to opravdu tak, tak místo obrovského $content se kopíruje buď "1" nebo "2", což je opravdu rychlé jako blesk.[7] Aha, už jsem ty benchmarky opravil, takže už dostávám ony očekávané výsledky.
Jinak takovéto "bashophpmaso" obvykle nedělám, ale pro benchmark mi přišlo celkem praktické.
Komentáře jsou uzavřeny.