Подтвердить что ты не робот

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

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

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

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

--- VS ---

$collection->each(function ($item) {
    // Some code
});
4b9b3361

Ответ 1

Оператор

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

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

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

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

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

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

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

.each в Laravel 5.1

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

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

Ответ 2

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

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

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

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

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

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

Итак... какой из них я должен использовать?

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

Конструкция 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/