Красноречивые коллекции: каждый против foreach

Возможно, это не вопрос, связанный с коллекциями Eloquent, но он просто ударил меня во время работы с ними. Допустим, у нас есть объект $collection который является экземпляром Illuminate\Support\Collection .

Теперь, если мы хотим перебрать его, каковы плюсы и минусы использования each() с закрытием по сравнению с обычным foreach . Есть ли?

 foreach ($collection as $item) { // Some code } --- VS --- $collection->each(function ($item) { // Some code }); 

Related of "Красноречивые коллекции: каждый против foreach"

Оператор foreach должен использоваться как своего рода способ циклического перемещения по коллекции и выполнения на ней какой-то логики. Если что-то в нем влияет на другие вещи в программе, то используйте этот цикл.

Метод .each использует array_map для циклического array_map по каждому из объектов в коллекции и выполнения замыкания на каждом из них. Затем он возвращает результирующий массив. Это ключ! .each следует использовать, если вы хотите каким-то образом изменить коллекцию. Может быть, это массив автомобилей, и вы хотите сделать модельный верхний регистр или нижний регистр. Вы просто передадите закрытие методу .each который принимает объект, и вызывает strtoupper() в модели каждого объекта Car. Затем он возвращает коллекцию с внесенными изменениями.

Мораль этой истории такова: используйте метод .each чтобы каким-то образом изменить каждый элемент массива; используйте цикл foreach чтобы использовать каждый объект для воздействия на какую-либо другую часть программы (используя некоторый логический оператор).

ОБНОВЛЕНИЕ (7 июня 2015 г.)

Как сказано так ясно (см., Что я там сделал?) Ниже, приведенный выше ответ немного выключен. Метод .each с использованием array_map никогда не использовал вывод из вызова array_map . Таким образом, новый массив, созданный array_map , не будет сохранен в Collection . Чтобы изменить его, вам лучше использовать метод .map , который также существует в объекте Collection .

Использование инструкции foreach для итерации по каждому из них имеет немного больше смысла, потому что вы не сможете обращаться к переменным за пределами Closure, если вы не будете use инструкцию use , что для меня кажется неудобным.

Реализация, когда первый ответ был первоначально написан, можно найти здесь .

.each в Laravel 5.1

В новом .each о котором они говорят ниже, больше не используется array_map . Он просто выполняет итерацию через каждый элемент в коллекции и вызывает переданный в $callback , передавая ему элемент и его ключ в массиве. Функционально, похоже, работает одинаково. Я считаю, что использование цикла foreach имеет смысл при чтении кода. Тем не менее, я вижу преимущества использования .each потому что он позволяет вам объединять методы вместе, если это щекочет ваше воображение. Он также позволяет вам возвращать false из обратного вызова, чтобы оставить цикл раньше, если ваша бизнес-логика требует от вас возможности.

Для получения дополнительной информации о новой реализации проверьте исходный код .

В существующих ответах много запутанной дезинформации.

Короткий ответ

Короткий ответ: нет никакой существенной разницы между использованием .each() и foreach для итерации по коллекции Laravel. Оба метода достигают того же результата.

Как насчет изменения элементов?

Независимо от того, .each() ли вы элементы, не имеет значения, используете ли вы .each() против foreach . Они оба делают (и не делают!) Позволяют изменять элементы в коллекции в зависимости от того, о каких типах предметов мы говорим.

  • Изменение элементов, если коллекция содержит объекты : если коллекция представляет собой набор объектов PHP (например, Eloquent Collection), либо .each() или foreach позволяют изменять свойства объектов (например, $item->name = 'foo' ). Это просто из-за того, что объекты PHP всегда действуют как ссылки. Если вы пытаетесь заменить весь объект другим объектом (менее распространенным сценарием), используйте вместо него .map() .
  • Изменение элементов, если коллекция содержит не объекты : это менее распространено, но если ваша коллекция содержит не объекты, такие как строки, .each() не дает вам способ изменить значения элементов коллекции. (Возвращаемое значение закрытия игнорируется. .map() Вместо этого используйте .map() .

Итак … какую пользу я должен использовать?

В случае, если вам интересно о производительности, я провел несколько тестов с большими коллекциями как элементов Eloquent, так и набора строк. В обоих случаях использование foreach было быстрее, чем .each() . Но мы говорим о микросекундах. В большинстве сценариев реальной жизни разница в скорости будет незначительной по сравнению с временем, требуемым для доступа к базе данных и т. Д.

Это в основном сводится к вашим личным предпочтениям. Использование .each() хорошо, потому что вы можете .where(...).each(...) несколько операций вместе (например .where(...).each(...) ). Я имею тенденцию использовать оба в своем собственном коде только в зависимости от того, что кажется самым чистым для каждой ситуации.

Вопреки тому, что говорят два других ответа, Collection::each() не меняет значения элементов в коллекции, технически говоря. Он использует array_map() , но не сохраняет результат этого вызова.

Если вы хотите изменить каждый элемент в коллекции (например, чтобы отнести их к объектам как Damon в комментарии к принятому ответу), вы должны использовать Collection::map() . Это создаст новую коллекцию, основанную на результате базового вызова array_map() .

Полезнее использовать последнее: each ().

Вы можете настроить условия и написать более выразительный код, например:

$ ПРИМЕР-> каждый () -> карта () -> фильтр ();

Это приблизит вас к декларативному программированию, где вы сообщаете компьютеру, что делать, а не как выполнять.

Некоторые полезные статьи:

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

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

Конструкция foreach () не позволяет вам изменять значение элемента массива, которое повторяется, если вы не передадите массив по ссылке.

 foreach ($array as &$value) $value *= $value; 

Каждый () метод eloquent обертывает функцию PHP array_map (), которая позволяет это.

Как и в предыдущих ответах, вы должны использовать foreach (), если у вас есть другая мотивация. Это связано с тем, что производительность foreach () намного лучше, чем array_map ().

http://willem.stuursma.name/2010/11/22/a-detailed-look-into-array_map-and-foreach/