ugrás a tartalomhoz

érdekes foreach működés

mdesign · 2007. Nov. 13. (K), 10.23
Sziasztok!

Egy érdekes működésre lettem figyelmes. Lehet, hogy ez normális. Ez esetben homályosítsatok fel lécci.

<?php

// tömb feltöltése
$array = array();
for($i = 0; $i < 5; $i++) { $array[] = $i; }

var_dump($array);

// Iterálás referenciaátadással
foreach( $array as &$element) { }
echo "<hr/>";
var_dump($array);

// Iterálás referenciaátadás nélkül
foreach( $array as $element) { }
echo "<hr/>";
var_dump($array);

?>
Ezt lefuttatva a végeredmény a következő:

array(5) { [0]=>  int(0) [1]=>  int(1) [2]=>  int(2) [3]=>  int(3) [4]=>  int(4) } 
array(5) { [0]=>  int(0) [1]=>  int(1) [2]=>  int(2) [3]=>  int(3) [4]=>  ∫(4) } 
array(5) { [0]=>  int(0) [1]=>  int(1) [2]=>  int(2) [3]=>  int(3) [4]=>  ∫(3) }
A kérdésem a következő: Miért íródik felül az utolsó érték az utolsó előtti értékkel referenciaátadásos iterálás után, ha újra ugyanazokkal változónevekkel. (Ha megváltoztatom a második ciklusban az elemnek szánt változónevet, akkor az értékek helyesek maradnak.)

Én úgy tudtam, hogy a foreachen belül deklarált változók a foreachet elhagyva elhalnak.

Amennyiben az 1. foreach után beszúrok egy unset($element); sort, minden rendben működik. Csak ezt azért nem értem, mert ezen a "szinten" ilyen változót nem is hoztunk létre.

Bónuszkérdés: mi az a jel a második és harmadik var_dump-olt tömb utolsó eleme előtt? Miért nem ismeri fel int-nek?

Üdv Karesz
 
1

parancssor

zila · 2007. Nov. 13. (K), 10.45
Az ilyen jellegű teszteket érdemes parancssorban kipróbálni (vagy a html forrást megtekinteni), hogy a html speciális karakterei ne érvényesüljenek. (&int az pont az a jel amit te látsz :)

Itt az kimenet parancssorból (ezen látszik, hogy az utolsó értékek referenciák):
gimli:Sites zila$ php array.php 
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
}
-------------
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  &int(4)
}
-------------
array(5) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  &int(3)
}
A foreach ciklusváltozója az utolsó értékkel megmarad a ciklus lefutása után. Az valóban érdekes, hogy egy sima forech módosítja az eredeti tömböt... A válasz engem is érdekel :)
2

közben

mdesign · 2007. Nov. 13. (K), 10.53
Szia!

Közben rájöttem, hogy &int -et jelentheti, mivel kipróbáltam sztringgel is és ott egyértelműen látszott a &string megjelölés...

Akkor mostmár ketten vagyunk akik kiváncsiak rá:)
3

foreachben deklarált változó

pappi · 2007. Nov. 13. (K), 11.20
szerintem nincs külön változó névtere a foreachnek, azaz a változók (itt $element) a foreach után is megmaradnak és ez kavar be a második foreachnek.

Ettől függetlenül szerintem ez egyértelműen bug.
(Update: http://bugs.php.net/bug.php?id=29992 de szerintük nem bug)

De van itt még érdekesebb is:
 <?php

 // tömb feltöltése
 $a = array();
 for($i = 0; $i < 5; $i++) { $a[] = $i; }
 var_dump($a);

 echo 'Iterálás referenciaátadással' . "\n";
 foreach( $a as &$e) {}
 var_dump($a);

 echo 'while each' . "\n";
 reset($a);
 while (list(, $e) = each($a)) { var_dump($e); }
 var_dump($a); 

 echo 'Iterálás referenciaátadás nélkül' . "\n";
 foreach( $a as $e) {}
 var_dump($a);


?>
4

manuálban benne van

flash42 · 2007. Nov. 13. (K), 20.53
érdekes ez a cucc, egyáltalán nem értek php-hez de örömmel látom, hogy viccesebb pointer bugok vannak benne mint a c-ben:) a megoldás adódik amúgy a php manualból ami elérhető az internet nevű sz*rról. ez egy cseppet levon a topic értelméből.

szóval a második foreachben a belső változó valójában egy hivatkozás az előző bejárás miatt az utolsó elemre a bejárandó tömbből. ez azért van így mert referenciát adsz át (az első esetben) és a foreachen kívül is elérhető lesz ez a változó. az, hogy elérhető az egy dolog, de ráadásul a bejárás végén (lsd.: foreach működése) a pointer értéke az utolsó elemen lesz (erre fog mutatni a változó), majd terminál a ciklus. utána az utolsó eleme az utolsó elem referencia lesz mivel minden változónév referencia lesz ha arra a változóra készült egy referencia (php manual). a második bejárás során az utolsó előtti értékkel fog állni az utolsó elemre mutató referencia az utolsó előtti elem látogatásakor, mivel ezt az értéket kapja épp meg (a bejárás során mindig az aktuális elemét kapja meg a tömbnek:)). majd elérünk az utolsó elemre amikoris a változó értéke, az utolsó előtti elem lesz, mivel az utolsó elem értéke az előbb az utolsó előtti elem lett. ez egy referencia lesz, mivel amire van referencia maga is referencia, tehát az utolsó helyen az utolsó előtti elem mint referencia fog állni. érdekes mókás vicces.
5

Ezt érti valaki?

Fraki · 2007. Nov. 14. (Sze), 00.17
Ezt érti valaki?
6

igen

mdesign · 2007. Nov. 14. (Sze), 09.42
Mea Culpa.
Tényleg benne van a manuálban és bug report is indult róla.

Értem mostmár, hogy miért - bár nekem valahogy az angol magyarázat könnyebben emészthető volt:)

Php fejlesztők sem értenek 100%-ban egyet ezen a viselkedésen, de ahogy látom ez már így marad.

Üdv Mindenkinek!
7

változók működése PHP-ban

Hodicska Gergely · 2007. Nov. 14. (Sze), 11.35
Teljesen logikus, ha ismered, hogy hogyan működik a referencia a PHP-ban. Már egyszer említettem, hogy tervben van egy cikk a PHP változókról, megpróbálom a hétvégén összeütni. Az persze más dolog, hogy szerintem is ez egy elég veszélyes működés, én nem egy piros warninggal kellett volna megoldani a manuálban.


Üdv,
Felhő
8

unset

flash42 · 2007. Nov. 14. (Sze), 11.57
nincs értelme gondolkozni rajta, ez inkább érdeklődő ujjongás volt, mintsem magyarázat. tényleg fennvan angolul, csak elcsentem. a megoldás ottvan, unset-et illik használni, hogy megszűntesse a rendszer a referenciát és így megszabadulhat az ember a mellékhatásoktól.