2013-09-07 11 views
7

Ich muss ein Array zweimal durchlaufen - einmal um seine Werte zu ändern, und einmal, um seinen Inhalt in HTML anzuzeigen. Leider gerate ich in Schwierigkeiten. Ich habe ein Testszenario erstellt, um das Problem zu veranschaulichen.PHP-Problem mit Schleifen über ein Array zweimal mit foreach und übergeben Wert durch Referenz

$cases = array(
    array('caseStyle' => 'case style 1', 'caseNum' => 'case01'), 
    array('caseStyle' => 'case style 2', 'caseNum' => 'case02'), 
    array('caseStyle' => 'case style 3', 'caseNum' => 'case03'), 
    array('caseStyle' => 'case style 4', 'caseNum' => 'case04'), 
    array('caseStyle' => 'case style 5', 'caseNum' => 'case05'), 
    array('caseStyle' => 'case style 6', 'caseNum' => 'case06') 
); 

foreach ($cases as $k => &$v) { 
    $v['caseNum'] = ucwords($v['caseNum']); 
} 

foreach ($cases as $k => $v) { 
    echo $v['caseNum'] . ' - ' . $v['caseStyle'] . '<br/>'; 
} 

Diese Ausgänge:

Case01 - case style 1 
Case02 - case style 2 
Case03 - case style 3 
Case04 - case style 4 
Case05 - case style 5 
Case05 - case style 5 

Beachten Sie die Werte für den letzten Punkt sind falsch.

Wenn während der zweiten Iteration ich foreach($cases as $k => $d) statt foreach($cases as $k => $v) oder wenn ich $v vor der zweiten Iteration unset (unset($v)) geht alles in Ordnung. Das ist faszinierend. Was vermisse ich?

+3

Warum müssen Sie dies in zwei Schleifen tun? Warum nicht beides beim ersten Mal machen? – DiMono

+0

Im eigentlichen Code ist das Array ein sperriges schlechtes Array von Arrays mit Zeilen, die von der Datenbank zurückgegeben werden. In der ersten Iteration räume ich auf, füge Standardwerte für fehlende Werte hinzu, ändere Formate wo nötig und füge zusätzliche Felder hinzu, die aus anderen Tabellen stammen. Die zweite Iteration ist, wenn ich die HTML-Seite mit Werten aus dem Array (das ist Legacy-Code - HTML und PHP alle in einer Datei, keine Vorlagen :() – longwing

+1

Das bedeutet immer noch nicht, dass Sie es nicht tun können Wenn Sie Werte aus dem Array verwenden müssen, bevor Sie sie anzeigen, können Sie die Ausgabe in eine Variable puffern und dann bei Bedarf die Variable ausgeben. Wenn Komplexität ein Problem verursacht, entfernen Sie die Komplexität;) – DiMono

Antwort

2

Try this:

foreach ($cases as $k => &$v) { 
    $cases[$k]['caseNum'] = ucwords($v['caseNum']); 
    echo $cases[$k]['caseNum'] . ' - ' . $cases[$k]['caseStyle'] . '<br/>'; 
} 
+0

Hm habe diese Frage auch gelesen und versucht, das auf XAMPP zu reproduzieren. Während der ursprüngliche Code nicht mein erster Versuch sein würde, versuchte ich herauszufinden, was falsch läuft. Ist nicht zu einem Ergebnis gekommen, aber Ihre Lösung funktioniert definitiv. – grobmotoriker

+0

Das haben wir in den Kommentaren der Frage diskutiert. – DiMono

+0

@DiMono entweder (eine Schleife oder zwei), das wird funktionieren. – undone

0

Lassen Sie es mich wissen dies ist Ihre Lösung:

foreach ($cases as $k => &$v){ 
    foreach($v as &$value){ $value = ucwords($value); } 
echo $v['caseNum'] . ' - ' . $v['caseStyle'] . '<br/>'; 
} 
+0

Danke für das Teilen. Sobald Sie $ v als Referenz übergeben haben, werden alle untergeordneten Elemente automatisch als Referenz übergeben. Keine Notwendigkeit, dies explizit zu tun. – longwing

+0

Sie sind willkommen, tun Sie es selbst, um das Ergebnis zu sehen;), – 01e

+0

Im zweiten foreach die $ v-Variable behandeln als $ Fälle! Was Sie tun, ist, die Werte von $ v in $ value zu referenzieren, keine Kopie von ihnen. – 01e

15

Wenn Sie eine foreach Schleife ausführen, bleiben die Variablen in der (), nachdem die Schleife erfolgt. Das bedeutet, dass Sie nach Abschluss der ersten Schleife var_dump($v) abrufen und die Werte abrufen können, die nach der letzten Iteration in der ersten Schleife enthalten waren. Dies ist der Fall, unabhängig davon, ob es sich um eine Referenz (&$v) oder eine normale Variable ($v) handelt.

Wenn es jedoch eine Referenz in der ersten Schleife ist, bleibt es eine Referenz, es sei denn, es ist nicht festgelegt. Das heißt, wenn Sie die zweite Schleife eingeben, überschreiben Sie die Referenz mit dem Wert des Array-Elements, das Sie gerade betrachten.

Denken Sie daran, was foreach($cases as $k => $v) wirklich bedeutet "nehmen Sie den Schlüssel für dieses Element in $ cases und zuweisen, dass zu $ ​​k, und nehmen Sie den Wert für dieses Element und zuweisen Sie es $ v)". Da $ v immer noch eine Referenz auf das letzte Element im Array ist, anstatt den Wert einer neuen Variablen $ v zu setzen, aktualisieren Sie den Wert, auf den bereits $ v verweist.

Was das bedeutet, ist, wenn wir $ Fällen vereinfachen einfach ['a', 'b', 'c', 'd'] sein, nach dem ersten Mal durch die zweite foreach ist $ Fälle jetzt ['a', 'b', 'c', 'a'], weil Sie das Element in $ Fällen, dass $ v Punkte zugewiesen haben - die letzte - um den gleichen Wert wie die erste zu haben. Das zweite Mal durch, es ist ['a', 'b', 'c', 'b']. Das dritte Mal ist es ['a', 'b', 'c', 'c']. Dann, das letzte Mal bis Sie es sich selbst zuweisen, und zu diesem Zeitpunkt hält es den Wert 'c'.

Dies ist wirklich nur ein Fall von PHP funktioniert wie erwartet. Die Lösung ist unset($v), sobald die erste Schleife abgeschlossen ist, um sicherzustellen, dass Sie bei der nächsten Verwendung von $ v eine neue Variable anstelle einer vorhandenen Referenz verwenden.

Um dies in Aktion zu sehen:

Kopf auf mehr als auf http://phpfiddle.org/ und den folgenden Code einfügen, und führen Sie es; Sie sehen in der Ausgabe, dass $v beibehalten wird, nachdem die erste Schleife abgeschlossen ist, und dass der Wert $cases[5] jedes Mal durch die zweite Schleife ändert.

$cases = array(
    array('caseStyle' => 'case style 1', 'caseNum' => 'case01'), 
    array('caseStyle' => 'case style 2', 'caseNum' => 'case02'), 
    array('caseStyle' => 'case style 3', 'caseNum' => 'case03'), 
    array('caseStyle' => 'case style 4', 'caseNum' => 'case04'), 
    array('caseStyle' => 'case style 5', 'caseNum' => 'case05'), 
    array('caseStyle' => 'case style 6', 'caseNum' => 'case06') 
); 

foreach ($cases as $k => &$v) { 
    $v['caseNum'] = ucwords($v['caseNum']); 
} 
var_dump($v); 
echo "<br />"; 
foreach ($cases as $k => $v) { 
    print_r($cases); 
    echo "<br />"; 
    echo $k . ': ' . $v['caseNum'] . ' - ' . $v['caseStyle'] . '<br/>'; 
} 
+0

Absolut! Danke DiMono. Ich schlief darüber nachdenken und wachte nur mit der gleichen Einsicht :) – longwing

+0

Gern geschehen. Es ist eine gute Form, eine Antwort zu akzeptieren, sobald Sie es gefunden haben, nebenbei bemerkt. – DiMono

Verwandte Themen