webrebel html css javascript laravel oop php mysql wordpress kurz

Bug v poli

napísal , 9 Oct 2010 [ PHP ]

...alebo skôr feature? Keď v PHP používate foreach s referenciou (&), treba si dávať veľký pozor. Môžu sa diať vcelku záhadné veci. Zoberme si takýto príklad:

$ciselka = array(1,2,3,4,5,6);

foreach ($ciselka as &$cislo) $cislo *= 10;

foreach ($ciselka as $cislo) echo "$cislo ";

V prvom foreach cykle všetky čísla v poli vynásobíme desiatimi a v druhom ich vypíšeme - triviálna vec, takže výsledok je úplne jasný:
10 20 30 40 50 60

Alebo aj nie? Ak to skúsite naozaj spustiť v PHP, uvidíte niečo trocha iné:
10 20 30 40 50 50 - WTF is goin' on?

Prečo sú posledné 2 prvky rovnaké? Cyklus foreach funguje tak, že do pomocnej premennej ($cislo) vždy kopíruje aktuálny prvok poľa a podľa toho, či pred ňu nedáme alebo dáme "&" sa buď do nej skopíruje hodnota aktuálneho prvku alebo odkaz/pointer na aktuálny prvok. V prvom cykle úkladáme do pomocnej premennej odkazy na prvky poľa, takže po skončení je v premennej $cislo odkaz na posledný prvok.

Ak by sme teraz premennej $cislo priradili hocijakú hodnotu, zmenila by sa aj hodnota posledného prvku poľa. A presne toto sa deje pri druhom cykle foreach - postupne, ako prechádzame poľom, sa priraďujú premennej $cislo hodnoty 10, 20, 30, 40, 50. Takže je logické, že keď prijdeme na posledný prvok, je v ňom hodnota predposledného prvku.

Ako tomu zabrániť? Nuž velice jednoducho. :p
Za prvý foreach stačí napísať unset($cislo). Premenná prestane existovať, odkaz sa zruší a v druhom cykle sa úplne nanovo vytvorí premenná $cislo, takže sa nič nebude prepisovať.

Je diskutabilné, či sa toto vôbec dá označiť ako bug... Na jednej strane prakticky nepredvídateľné, ale na druhej aj celkom logické. Asi preto je to v PHP nezmenené odvtedy ako existuje foreach s referenciou.

napísal , 9 Oct 2010

čo ty na to?

komentuj