web-dev-qa-db-ger.com

Eloquente Sammlungen: jeweils vs foreach

Vielleicht keine spezifische Frage für Eloquent-Kollektionen, aber es hat mich einfach getroffen, als ich mit ihnen gearbeitet habe. Nehmen wir an, wir haben ein $collection-Objekt, das eine Instanz von Illuminate\Support\Collection ist. 

Wenn wir nun darüber iterieren wollen, was sind die Vor- und Nachteile der Verwendung von each() mit einer Schließung im Vergleich zu einem regulären foreach. Gibt es irgendwelche?

foreach ($collection as $item) {
    // Some code
}

--- VS ---

$collection->each(function ($item) {
    // Some code
});
42
Niklas Modess

Eine foreach-Anweisung sollte als eine Art Weg verwendet werden, um eine Auflistung zu durchlaufen und eine Art Logik darauf auszuführen. Wenn das, was sich darin befindet, andere Dinge im Programm beeinflusst, dann verwenden Sie diese Schleife. 

Die .each-Methode verwendet array_map, um jedes der Objekte in der Auflistung zu durchlaufen und für jedes eine Schließung durchzuführen. Dann wird das resultierende Array zurückgegeben. Das ist der Schlüssel! .each sollte verwendet werden, wenn Sie die Sammlung auf irgendeine Weise ändern möchten. Vielleicht ist es eine Reihe von Autos und Sie möchten das Modell in Groß- oder Kleinschreibung erstellen. Sie würden einfach eine Schließung an die .each-Methode übergeben, die das Objekt übernimmt und strtoupper() für das Modell jedes Car-Objekts aufruft. Anschließend wird die Sammlung mit den vorgenommenen Änderungen zurückgegeben. 

Die Moral der Geschichte ist folgende: Verwenden Sie die .each-Methode, um jedes Element im Array auf irgendeine Weise zu ändern. Verwenden Sie die foreach-Schleife, um jedes Objekt zu verwenden, um einen anderen Teil des Programms zu beeinflussen (unter Verwendung einer Logikanweisung).

UPDATE (7. Juni 2015)

Wie Eloquently (siehe, was ich dort gemacht habe?) Weiter unten gesagt, ist die obige Antwort etwas falsch. Die .each-Methode, die array_map verwendet, hat nie die Ausgabe des array_map-Aufrufs verwendet. Das von array_map erstellte neue Array würde also nicht in der Collection gespeichert. Um dies zu ändern, sollten Sie die .map-Methode verwenden, die auch in einem Collection-Objekt vorhanden ist.

Die Verwendung einer foreach-Anweisung zum Durchlaufen der einzelnen Elemente ist etwas sinnvoller, da Sie nur dann auf Variablen außerhalb des Closures zugreifen können, wenn Sie eine use-Anweisung verwenden, die mir unangenehm erscheint.

Die Implementierung, als die obige Antwort ursprünglich geschrieben wurde, kann hier gefunden werden.

.each in Laravel 5.1

Der neue .each, über den sie unten sprechen, verwendet array_map nicht mehr. Es durchläuft einfach jedes Element in der Auflistung und ruft das in $callback übergebene Element auf, wobei das Element und der Schlüssel im Array übergeben werden. Funktionell scheint es gleich zu funktionieren. Ich glaube, eine foreach-Schleife wäre beim Lesen des Codes sinnvoller. Ich sehe jedoch die Vorteile der Verwendung von .each, da Sie hier Methoden miteinander verketten können, wenn dies Ihren Vorstellungen entspricht. Außerdem können Sie den Callback zurückgeben, um die Schleife vorzeitig zu verlassen, wenn Ihre Geschäftslogik dies erfordert.

Weitere Informationen zur neuen Implementierung finden Sie unter dem Quellcode .

48
searsaw

Die vorhandenen Antworten enthalten viele verwirrende Fehlinformationen.

Die kurze Antwort

Die kurze Antwort lautet: Es gibt keinen wesentlichen Unterschied zwischen der Verwendung von .each() und foreach zum Durchlaufen einer Laravel-Sammlung. Beide Techniken erzielen das gleiche Ergebnis.

Was ist mit dem Ändern von Elementen?

Ob Sie Elemente ändern oder nicht, spielt keine Rolle, ob Sie .each() oder foreach verwenden. Beide erlauben (und tun es nicht!). Sie können Elemente in der Sammlung ändern, je nachdem, um welche Art von Elementen es sich handelt.

  • Ändern von Elementen, wenn die Collection Objekte enthält : Wenn es sich bei der Collection um eine Gruppe von PHP - Objekten handelt (z. B. eine Eloquent Collection), können Sie entweder .each() oder foreach die Eigenschaften der Objekte ändern (z. B. $item->name = 'foo'). . Das liegt einfach daran, dass PHP -Objekte immer als Referenzen fungieren. Wenn Sie versuchen, das gesamte Objekt durch ein anderes Objekt zu ersetzen (ein seltenes Szenario), verwenden Sie stattdessen .map().
  • Ändern von Elementen, wenn die Collection Nichtobjekte enthält : Dies ist weniger üblich. Wenn Ihre Collection jedoch Nichtobjekte enthält, z. B. Zeichenfolgen, bietet Ihnen .each() keine Möglichkeit, die Werte der Sammlungselemente zu ändern. (Der Rückgabewert der Schließung wird ignoriert.) Verwenden Sie stattdessen .map().

Also ... welches soll ich verwenden?

Falls Sie sich über die Leistung wundern, habe ich mehrere Tests mit einer großen Sammlung von Eloquent-Elementen und einer Reihe von Zeichenketten durchgeführt. In beiden Fällen war foreach schneller als .each(). Aber wir reden hier von Mikrosekunden. In den meisten realen Szenarien wäre der Geschwindigkeitsunterschied im Vergleich zu der Zeit, die der Zugriff auf die Datenbank usw. benötigt, nicht signifikant.

Es hängt hauptsächlich von Ihren persönlichen Vorlieben ab. Die Verwendung von .each() ist Nizza, da Sie mehrere Operationen miteinander verketten können (z. B. .where(...).each(...)). Ich neige dazu, beides in meinem eigenen Code zu verwenden, je nachdem, was für jede Situation am saubersten erscheint.

13
orrd

Im Gegensatz zu den beiden anderen Antworten ändert Collection::each()nicht die Werte der Elemente in der Sammlung, technisch gesehen. Es verwendet array_map(), speichert jedoch nicht das Ergebnis dieses Aufrufs.

Wenn Sie jedes Element in einer Auflistung ändern möchten (z. B. um sie in einem Kommentar zu der schnell akzeptierten Antwort in Objekte als Damon umzuwandeln), sollten Sie Collection::map() verwenden. Dadurch wird eine neue Sammlung erstellt, die auf dem Ergebnis des zugrunde liegenden Aufrufs von array_map() basiert.

3
Jake S

Es ist vorteilhafter, letzteres zu verwenden: each ().

Sie können Bedingungen verketten und klareren Code schreiben, z.

$ example-> each () -> map () -> filter ();

Dies bringt Sie näher zur deklarativen Programmierung, in der Sie dem Computer mitteilen, was er tun soll, anstatt zu wissen, was er tun soll.

Einige nützliche Artikel:

https://martinfowler.com/articles/collection-pipeline/

https://adamwathan.me/refactoring-to-collections/

0
Nik K