Verhalten von foreach

Verhalten von foreach

am 19.04.2008 17:32:23 von Oliver Block

Hallo Gruppe,

von Zeit zu Zeit beobachte ich Probleme in der Verwendung von foreach.
Gerade kürzlich traten dabei erneut Probleme auf. Da ich die bisher
durch Verwendung von for auffangen konnte habe ich mich bisher nicht
weiter darum gekümmert.

Nun zum Problem. In einer Funktion wird ein numerisches Array zwei Mal
nacheinander mittels foreach durchlaufen:

foreach($arr as &$val) {
....
if($bedingung == true)
$val = null;
....
}

foreach($arr as $val) {
....
if(!is_null($val))
$str .= ' ' . $val;

....
}

Beim zweiten Durchlauf war $str stets leer, obwohl $arr mindestens ein
Element hatte, das nicht null war. Eine Änderung der zweiten Schleife in

for($i=0,$n=count($arr); $i<$n; $i++) {
....
if(!is_null($arr[$i]))
$str .= ' ' . $arr[$i];
....
}

hat das Problem, wie erwähnt, behoben. Allerdings habe ich bisher nicht
verstanden, wo mein/der Fehler liegen könnte.

- Der interne Zeiger soll lt. Doku immer bei der Verwendung von foreach
zurückgesetzt werden.
- Es liegt kein Hinweis darauf vor, daß foreach nur mit assoziativen
Arrays verwendet werden sollte.

Hat jemand eine Erklärung?

Gruß,

Oliver Block

Re: Verhalten von foreach

am 19.04.2008 18:29:20 von Christoph Herrmann

Oliver Block schrieb:
> Hat jemand eine Erklärung?

was gibt denn "var_dump($arr);" jeweils vor den Schleifen aus?

--
Mit freundlichen Grüßen,
Christoph Herrmann

http://dragonprojects.de/

Re: Verhalten von foreach

am 19.04.2008 19:05:35 von Oliver Block

Christoph Herrmann schrieb:
> Oliver Block schrieb:
>> Hat jemand eine Erklärung?
>
> was gibt denn "var_dump($arr);" jeweils vor den Schleifen aus?
>

$arr gibt vor der zweiten foreach-Anweisung z.B. zwei Elemente, bei
denen [0] ein String ist und [1] => NULL.

Wenn dann die Schleife durchlaufen wird, gibt var_dump (innerhalb des
foreach-Blocks) für beide Elemente [0], [1] NULL aus.

Hier fällt auf, dass die Anzahl der Durchläufe passt. Allerdings ist der
Wert NULL, was eben nicht richtig ist.

Re: Verhalten von foreach

am 19.04.2008 19:08:32 von Thomas Mlynarczyk

Oliver Block schrieb:

> foreach($arr as &$val) {
> ...
> if($bedingung == true)
> $val = null;
> ...
> }
>
> foreach($arr as $val) {
> ...
> if(!is_null($val))
> $str .= ' ' . $val;
>
> ...
> }

Nur ein Versuch: unset( $val ) zwischen den beiden Schleifen.

Gruß,
Thomas

--
Ce n'est pas parce qu'ils sont nombreux à avoir tort qu'ils ont raison!
(Coluche)

Re: Verhalten von foreach

am 19.04.2008 19:47:58 von Claus Reibenstein

Oliver Block schrieb:

> foreach($arr as &$val) {

Hier setzt Du bei jedem Schleifendurchlauf eine Referenz auf das
jeweilige Feldelement. Nach dem Schleifenende referenziert $var also das
letzte Element des Arrays.

> foreach($arr as $val) {

Hier legst Du bei jedem Schleifendurchlauf eine Kopie des aktuellen
Elements auf $var. Da $var aber noch die Referenz auf das letzte
Feldelement enthält, landet diese Kopie auf eben diesem Element.

Dieses Verhalten ist kein Bug, sondern ein wohl definiertes und
dokumentiertes Feature.

Um dieses Problem zu lösen, musst Du vor der zweiten Schleife $var löschen:

unset($var);

Gruß. Claus

Re: Verhalten von foreach

am 19.04.2008 19:56:04 von Claus Reibenstein

Oliver Block schrieb:

> foreach($arr as &$val) {

Hier setzt Du bei jedem Schleifendurchlauf eine Referenz auf das
jeweilige Feldelement. Nach dem Schleifenende referenziert $val also das
letzte Element des Arrays.

> foreach($arr as $val) {

Hier legst Du bei jedem Schleifendurchlauf eine Kopie des aktuellen
Elements auf $val. Da $val aber noch die Referenz auf das letzte
Feldelement enthält, landet diese Kopie auf eben diesem Element.

Dieses Verhalten ist kein Bug, sondern ein wohl definiertes und
dokumentiertes Feature.

Um dieses Problem zu lösen, musst Du vor der zweiten Schleife $val löschen:

unset($val);

Gruß. Claus

Re: Verhalten von foreach

am 20.04.2008 00:04:51 von Oliver Block

Claus Reibenstein schrieb:
> Hier legst Du bei jedem Schleifendurchlauf eine Kopie des aktuellen
> Elements auf $val. Da $val aber noch die Referenz auf das letzte
> Feldelement enthält, landet diese Kopie auf eben diesem Element.

Das hört sich plausibel an.:) Ich hatte ja extra eine Referenz
verwendet, um die Werte ggf. verändern zu können. Ich hatte mir nur
keine Gedanken über den Geltungsbereich gemacht.


> Dieses Verhalten ist kein Bug, sondern ein wohl definiertes und
> dokumentiertes Feature.

ACK.

Gruss,

Oliver