php foreach ограничить количество итераций
foreach — ограничение количества циклов в переполнении стека
У меня есть цикл foreach, который мне нужно ограничить первыми 10 пунктами, а затем выйти из него.
Как бы я сделал это здесь?
Буду признателен за подробное объяснение.
Решение
Если вы хотите использовать foreach, вы можете добавить дополнительную переменную для контроля количества итераций. Например:
Другие решения
Вы можете просто перебрать array_slice($butters->users->user, 0, 10) (первые 10 элементов).
Используйте счетчик циклов и break когда вы хотите выйти.
На 10-й итерации цикл завершится в конце.
Существует несколько вариантов этого, и вам нужно выбрать одну вещь: хотите ли вы выполнить условие внешнего цикла или нет. Рассматривать:
Если вы выйдете из верхней части этого цикла, вы прочтете 11 строк. Если вы выйдете внизу, это будет 10. В обоих случаях тело цикла выполнялось 10 раз, но выполнение этой дополнительной функции может быть тем, что вы хотите, а может и нет.
Если вы уверены, что хотите сохранить foreach цикл, добавить счетчик:
поэтому каждый раз, когда выполняется ваш цикл, счетчик увеличивается, а когда он достигает 10, цикл прерывается.
Кроме того, вы можете переделать foreach цикл, чтобы быть for цикл, если это возможно.
Вы можете запустить счетчик перед вашим блоком foreach и проверить его в цикле, а затем отключить, если счетчик равен 10,
Мне очень нравится ответ VolkerK, но я не понимаю, почему он создает новый итератор, когда, скорее всего, у вас будет существующий массив. Просто хочу поделиться тем, как я это сделал.
Способы ограничить итерацию foreach
merlak
Новичок
Есть вывод массива в шаблоне(smarty):
выводит номер итерации, т.е. номер цикла(незнаю как правильно)
то же самое только с нуля
понятно что общее кол-во
Все они для работы со всем массивом, а мне нужно только с фактическим, т.е. с тем массивом, который был ограничен условием
Если написать типа:
Массив выводится типа: 2, 5, 11, 4, 3, 21
Так вот нужно чтобы из этих чисел он делал ограничение до 5 итераций
Есть ещё
но тоже не получилось понять. Это вроде типа счётчика который выводит фактический вывод. Т.е. можно было бы if totalcount
Lok’tar ogar
Жесть какая, вложенные условия запутывают
Сделай два обхода: в первом отфильтруй нужные значения и сохрани их в одну переменную в виде массива, а во второй выведи 5 значений из этого полученного массива
Реализуй сначало без шаблонизатора, потом реализуй на смарти что ли
merlak
Новичок
Жесть какая, вложенные условия запутывают
Сделай два обхода: в первом отфильтруй нужные значения и сохрани их в одну переменную в виде массива, а во второй выведи 5 значений из этого полученного массива
Реализуй сначало без шаблонизатора, потом реализуй на смарти что ли
Первый этап лучше реализовать в бэкенде.
Да, я при обработке данных базы в php файле, делал сортировку по критериям. Т.е. критерий был <$articlecat_id == 60>и всё работало, в шаблоне только надо было ограничить по итерации. Но у меня проблема, у меня не только один foreach, у меня их как минимум 6 должно быть.. Это типа новостные блоки и каждый должен с отдельным id выводиться и с определённым кол-вом.
А так, в пхп чтобы для 6 блоков сделать сортировку по критериям, надо много много писанины, дублировать переменные, класы, условия.. у меня ведь там чего только нет, и пагинации, и теги, и дата, и коменты, всё отображается в блоках. короче жуть там полная
Работа с циклами foreach, for, while в PHP
Учебник PHP
Практика
Важное
Регулярки
Работа с htaccess
Файлы, папки
Сессии и куки
Работа с БД
Практика по работе с БД в PHP
Перед чтением см. новые уроки раздела «Важное», которые появились выше.
Практика
Движок PHP
Продвинутые БД
Аутентификация
Практика
ООП и MVC
Абстрактные классы и интерфейсы
Трейты
ООП Магия
Практика
Практика: классы как набор методов
Циклы используются для того, чтобы некоторый участок кода выполнился несколько раз подряд.
Делается это с помощью циклов.
Есть три вида циклов: foreach, while и for. Давайте разберемся, как с ними работать и чем они отличаются друг от друга.
Цикл foreach
Цикл foreach используется для прохождения по всем элементам массива.
После команды foreach() должны идти фигурные скобки <>. Код, который лежит в этих скобках, называется телом цикла.
Этот код будет выполняться столько раз, сколько проходов сделает цикл. А он сделает столько проходов, сколько элементов у нашего массива.
Итак, синтаксис цикла foreach выглядит так:
Давайте решим следующую задачу: пусть дан массив $arr с пятью элементами, выведем столбец этих элементов с помощью цикла foreach.
Будем при каждом проходе цикла выводить на экран (с помощью echo) текущий элемент массива (тот, что лежит в переменной $elem), и ставить после него тег br, чтобы получался столбец элементов, а не строка:
Если вам нужны только значения ассоциативного массива и не нужны ключи, то $ключ=> можно не писать:
Цикл foreach имеет альтернативный синтаксис:
Как и в случае с конструкцией if-else, мы можем разорвать скобки PHP внутри цикла, далее написать что-то на HTML и опять открыть скобки PHP – в этом случае HTML код внутри цикла повторится столько раз, сколько проходов сделает цикл (в случае foreach – это количество элементов массива):
Цикл while
Цикл while будет выполняться до тех пор, пока верно (истинно) выражение, переданное ему параметром. Смотрите синтаксис:
Давайте выведем с помощью цикла while столбец цифр от одного до пяти.
Для этого введем переменную $i, которую будем использовать для того, чтобы остановить наш цикл.
Как мы это сделаем: перед циклом поставим ей значение 1, а внутри цикла будем при каждом проходе цикла увеличивать ее на единицу. Сначала она будет 1, потом 2, потом 3 и так далее.
Цикл for
Цикл for является альтернативой while. Он более сложен для понимания, но чаще всего его любят больше, чем while, за то, что он занимает меньше строчек.
Его синтаксис выглядит так:
ограничение количества запусков цикла в php
У меня есть цикл foreach, который мне нужно ограничить первыми 10 элементами, а затем вырваться из него.
Как бы я сделать это здесь?
был бы признателен за подробное объяснение.
7 ответов
Если вы хотите использовать foreach, вы можете добавить дополнительную переменную для контроля количества итераций. Например:
вы также можете использовать LimitIterator.
вы можете просто перебрать array_slice($butters->users->user, 0, 10) (первые 10 элементов).
используйте счетчик циклов и break когда вы хотите выйти.
на 10-й итерации цикл завершится в конце.
Если вы выйдете в верхней части этого цикла, вы прочитаете 11 строк. Если вы выйдете снизу, будет 10. В обоих случаях тело цикла выполняется 10 раз, но выполнение этой дополнительной функции может быть тем, что вы хотите, или нет.
если вы уверены, что хотите сохранить foreach цикл, добавьте счетчик:
таким образом, каждый раз, когда ваш цикл выполняется, счетчик увеличивается, и когда он достигает 10, цикл прерывается.
в качестве альтернативы вы можете переработать foreach петли для for петли, если это возможно.
вы можете запустить счетчик перед блоком foreach и проверить его в цикле и сломать, если счетчик равен 10, как так,
Мне очень нравится ответ VolkerK, но я не понимаю, почему он создает новый итератор, когда, скорее всего, у вас будет существующий массив. Просто хочу поделиться тем, как все закончилось.
О тонкостях работы foreach в PHP
В недавнем дайджесте интересных ссылок о PHP я обнаружил ссылку на комментарий Никиты Попова на StackOverflow, где он подробно рассказывает о механизме «под капотом» управляющей конструкции foreach.
Поскольку foreach действительно иногда работает более, чем странным образом, я счел полезным сделать перевод этого ответа.
Внимание: этот текст подразумевает наличие базовых знаний о функциональности zval’ов в PHP, в частности вы должны знать что такое refcount и is_ref.
foreach работает с сущностями разных типов: с массивами, с простыми объектами (где перечисляются доступные свойства) и с Traversable-объектами (вернее, объектами, у которых определен внутренний обработчик get_iterator). Здесь мы, в основном, говорим о массивах, но я скажу и об остальных в самом конце.
Прежде чем приступить, пара слов о массивах и их обходе, важная для понимания контекста.
Как работает обход массивов
Массивы в PHP являются упорядоченными хеш-таблицами (элементы хеша объединены в двусвязный список) и foreach обходит массив, следуя указанному порядку.
Таким образом, внешние указатели массива могут быть использованы только когда вы полностью уверены, что при обходе никакого пользовательского кода выполняться не будет. А такой код может оказаться в самом неожиданном месте, типа обработчика ошибок или деструктора. Вот почему в большинстве случаев PHP приходится использовать внутренний указатель вместо внешнего. Если бы это было иначе, PHP мог бы упасть из-за segmentation fault, как только пользователь начнет делать что-нибудь необычное.
Проблема внутреннего указателя в том, что он является частью HashTable. Так что, когда вы изменяете его, HashTable меняется вместе с ним. И коль скоро обращение к массивам в PHP делается по значению (а не по ссылке), вы вынуждены копировать массив, чтобы в цикле обходить его элементы.
Простой пример, показывающий важность копирования (кстати, не такая большая редкость), это вложенная итерация:
Здесь вы хотите чтобы оба цикла были независимым, а не хитро перебрасывались одним указателем.
Итак, мы дошли до foreach.
Обход массива в foreach
Теперь вы знаете, для чего foreach приходится создавать копию массива, прежде чем обойти его. Но это явно не вся история. Сделает PHP копию или нет, зависит от нескольких факторов:
Итак, это первая часть тайны: функция копирования. Вторая часть это то, как текущая итерация выполняется, и она тоже довольно странная. «Обычный» образец итерации, который вы уже знаете (и который часто используется в PHP — отдельно от foreach) выглядит примерно так (псевдокод):
итерация foreach выглядит немного иначе:
Такой режим работы foreach также является причиной, по которой внутренний указатель массива переходит к следующему элементу, если текущий удалён, а не к предыдущему (как вы могли бы ожидать). Всё сделано так, чтобы отлично работать с foreach (но, очевидно, со всем остальным будет работать не так хорошо, пропуская элементы).
Последствия для кода
Первое следствие вышеописанного поведения в том, что foreach копирует итерируемый массив в многих случаях (медленно). Но отриньте страх: я пробовал удалить требование копирования и не смог увидеть ускорения работы нигде, кроме искусственных бенчмарков (в которых итерация происходила в два раза быстрее). Похоже, люди просто не итерируют достаточно много.
Второе следствие в том, что обычно не должно быть других следствий. Поведение foreach, в основном, вполне понятно пользователю и просто работает как следует. Вас не должно волновать, как происходит копирование (и происходит ли оно вообще), и в какой конкретно момент времени перемещается указатель.
И третье следствие — и тут мы как раз подходим к вашим проблемам — в том, что иногда мы видим очень странное поведение, которое трудно понять. Это происходит конкретно тогда, когда вы пытаетесь модифицировать сам массив, который вы обходите в цикле.
Большую коллекцию поведения в пограничных случаях, которые появляются, когда вы модифицируете массив в ходе итерации, можно найти в тестах PHP. Вы можете начать с этого теста, после чего изменять 012 на 013 в адресе, и так далее. Вы увидите, как поведение foreach будет проявляться в разных ситуациях (всякие комбинации ссылок и.т.д.).
А сейчас вернёмся к вашим примерам:
Та же ситуация, что и в первом тесте.
Но эти примеры недостаточно убедительны. Поведение начинает быть по настоящему непредсказуемым, когда вы используете current в цикле:
Теперь попробуем сделать небольшое изменение:
Здесь у нас is_ref=1, так что массив не копирован (так как и выше). Но сейчас когда есть is_ref, массив больше не нужно разделять, передавая по ссылке к current. Теперь current и foreach работают с одним массивом. Вы видите массив сдвинутым на единицу как раз из-за того, как foreach обращается с указателем.
То же самое вы увидите, когда будете делать обход массива по ссылкам:
Еще одна небольшая вариация, здесь мы присвоим наш массив еще одной переменной:
Итерация объектов
При итерации объектов имеет смысл рассмотреть два случая:
Объект не Traversable (вернее, не определен внутренний обработчик get_iterator)
В этом случае итерация происходит почти так же, как у массивов. Та же семантика копирования. Единственное отличие: foreach запустит некий дополнительный код, чтобы пропустить свойства, недоступные в текущей области видимости. Еще пара интересных фактов:
Объект Traversable
В этом случае всё, что сказано выше, не будет применяться никоим образом. Также PHP не будет копировать и не будет применять никакие трюки вроде увеличения указателя до прохода цикла. Я думаю что режим прохода по обходимому (Traversable) объекту куда более предсказуем и не требует дальнейшего описания.
Замена итерируемого объекта во время цикла
Другой необычный случай, который я не упомянул — PHP допускает возможность замены итерируемого объекта во время цикла. Вы можете начать с одним массивом и продолжить, заменив его на полдороге другим. Или начать с массивом, в затем заменить его объектом:
Как видите, PHP просто начал обходить другую сущность, как только произошла замена.
Изменение внутреннего указателя массива во время итерации
Последняя деталь поведения foreach, которую я не упомянул (потому что может быть использована для получения по настоящему странного поведения): что может случиться если попытаться изменить внутренний указатель массива во время прохода цикла.
Тут вы можете получить не то, что ожидали: если вызывать next или prev в теле цикла (в случае передачи по ссылке), вы увидите, что внутренний указатель переместился, но это никак не повлияло на поведение итератора. Причина в том, что foreach делает бекап текущей позиции и хеша текущего элемента в HashPointer после каждого прохода цикла. На следующей проходе foreach проверит, не менялась ли позиция внутреннего указателя и попытается восстановить ее, используя этот хеш.
Давайте посмотрим что означает «попытается». Первый пример показывает, как изменение внутреннего указателя не меняет режим foreach:
Теперь давайте попробуем сделать unset элементу, к которому обратится foreach при первом проходе (ключ 1):
Тут вы увидите, что счетчик сброшен, так как не удалось найти элемент с подходящим хешом.
Имейте в виду, хеш — всего лишь хеш. Случаются коллизии. Попробуем теперь так:
Работает так, как мы и ожидали. Мы удалили ключ EzFY (тот, где как раз был foreach), так что был сделан сброс. Также мы добавили дополнительный ключ, поэтому в конце мы видим 4.
И вот тут приходит неведомое. Что произойдёт, если заменить ключ FYFY с FYFZ? Давайте попробуем:
Сейчас цикл перешёл непосредственно к новому элементу, пропуская всё остальное. Это потому что ключ FYFY имеет коллизию с EzFY (вообще-то, все ключи из этого массива тоже). Более этого, элемент FYFY находится по тому же адресу в памяти, что и элемент EzFY который только что был удален. Так что для PHP это будет та же самая позиция с тем же хешом. Позиция «восстановлена» и происходит переход к концу массива.