Взрывание массива в параметре цикла foreach

foreach(explode(',' $foo) as $bar) { ... } 

против

 $test = explode(',' $foo); foreach($test as $bar) { ... } 

В первом примере он explode строку $foo для каждой итерации или PHP хранит ее в памяти взорван в своей временной переменной? С точки зрения эффективности, имеет ли смысл создавать дополнительные переменные $test или они почти равны?

Solutions Collecting From Web of "Взрывание массива в параметре цикла foreach"

Я мог бы дать обоснованное предположение, но давайте попробуем !

Я подумал, что есть три основных способа приблизиться к этому.

  1. взорваться и назначить перед входом в цикл
  2. взорваться внутри цикла, нет назначения
  3. string tokenize

Мои гипотезы:

  1. вероятно, потребляет больше памяти из-за назначения
  2. вероятно, идентичны # 1 или # 3, не уверены, какие
  3. вероятно, и более быстрый и значительно меньший объем памяти

Подход

Вот мой тестовый скрипт:

 <?php ini_set('memory_limit', '1024M'); $listStr = 'text'; $listStr .= str_repeat(',text', 9999999); $timeStart = microtime(true); /***** * {INSERT LOOP HERE} */ $timeEnd = microtime(true); $timeElapsed = $timeEnd - $timeStart; printf("Memory used: %s kB\n", memory_get_peak_usage()/1024); printf("Total time: %ss\n", $timeElapsed); 

И вот три версии:

1)

 // explode separately $arr = explode(',', $listStr); foreach ($arr as $val) {} 

2)

 // explode inline-ly foreach (explode(',', $listStr) as $val) {} 

3)

 // tokenize $tok = strtok($listStr, ','); while ($tok = strtok(',')) {} 

Результаты

Взрыв () Результаты тестов

Выводы

Похоже, некоторые предположения были опровергнуты. Разве вы не любите науку? 🙂

  • В целом картина любого из этих методов достаточно быстро для списка «разумного размера» (несколько сотен или нескольких тысяч).
  • Если вы повторяете что-то огромное , разница во времени относительно небольшая, но использование памяти может быть разным на порядок!
  • Когда вы explode() inline без предварительного назначения, по какой-то причине это немного медленнее.
  • Удивительно, что токенизация немного медленнее, чем явно итерация объявленного массива. Работая в таком небольшом масштабе, я считаю, что из-за накладных расходов на вызов вызова вызова функции strtok() каждая итерация. Подробнее об этом ниже.

С точки зрения количества вызовов функций, explode() действительно набирает токенизацию. O (1) vs O (n)

Я добавил бонус к диаграмме, где я запускаю метод 1) с вызовом функции в цикле. Я использовал strlen($val) , считая, что это будет относительно аналогичное время выполнения. Это подлежит обсуждению, но я только пытался сделать общий вывод. (Я только побежал strlen($val) и проигнорировал его вывод. Я не присваивал его никому, потому что назначение было бы дополнительной временной стоимостью.)

 // explode separately $arr = explode(',', $listStr); foreach ($arr as $val) {strlen($val);} 

Как видно из таблицы результатов, она становится самым медленным методом из трех.

Финальная мысль

Это интересно знать, но мое предложение состоит в том, чтобы делать все, что вы считаете наиболее читаемым / поддерживаемым. Только если вы действительно имеете дело с значительно большим набором данных, вы должны беспокоиться об этих микро-оптимизации.

В первом случае PHP взрывает его один раз и сохраняет его в памяти.

Влияние создания другой переменной или другого пути было бы незначительным. PHP Interpreter должен будет поддерживать указатель на местоположение следующего элемента, независимо от того, определены они пользователем или нет.

С точки зрения памяти это не изменит, потому что PHP использует копию для концепции записи .

Кроме того, я лично предпочел бы первый вариант – это строка меньше, но не менее читаемая (imho!).

Эффективность в каком смысле? Управление памятью или процессор? Процессор не повлиял бы на память – вы всегда можете делать $foo = explode(',', $foo)