Почему foreach так медленно?

PHPBench.com запускает быстрые тестовые скрипты на каждой странице. В тесте foreach, когда я загружаю его, foreach занимает от 4 до 10 раз больше времени, чем третий пример.

Почему построение родного языка, по-видимому, медленнее, чем выполнение самой логики?

Может быть, это связано с тем, что foreach работает над копией массива?

Или, может быть, это связано с тем, что при циклизации с foreach на каждой итерации внутренний указатель массива изменяется, чтобы указать на следующий элемент?

Цитирование соответствующей части страницы руководства foreach :

Примечание. Если массив не указан, foreach работает с копией указанного массива, а не с самим массивом. foreach имеет некоторые побочные эффекты для указателя массива.

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

(Я бы также сказал, что такая микро-оптимизация вообще не будет иметь никакого значения в реальном приложении – но, я думаю, вы уже знаете это и просто спрашивали из любопытства)

Существует также одна вещь, которая не чувствует себя хорошо в этом тесте: она делает только один раз ;; для «лучшего» теста было бы полезно протестировать все из них более одного раза – с таймингами порядка 100 микросекунд не так много, чтобы сделать огромную разницу.
(Учитывая, что первый тест варьируется от 300% до 500% при нескольких обновлениях …)

Для тех, кто не хочет нажимать, вот первый тест (я получил 3xx%, 443% и 529%) :

 foreach($aHash as $key=>$val) { $aHash[$key] .= "a"; } 

И третий (100%) :

 $key = array_keys($aHash); $size = sizeOf($key); for ($i=0; $i<$size; $i++) { $aHash[$key[$i]] .= "a"; } 

Извините, но на сайте было неправильно. Вот мой собственный скрипт, который показывает, что они почти одинаковы по скорости, и на самом деле foreach быстрее!

 <?php function start(){ global $aHash; // Initial Configuration $i = 0; $tmp = ''; while($i < 10000) { $tmp .= 'a'; ++$i; } $aHash = array_fill(100000000000000000000000, 100, $tmp); unset($i, $tmp); reset($aHash); } /* The Test */ $t = microtime(true); for($x = 0;$x<500;$x++){ start(); $key = array_keys($aHash); $size = sizeOf($key); for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= "a"; } print (microtime(true) - $t); print ('<br/>'); $t = microtime(true); for($x = 0;$x<500;$x++){ start(); foreach($aHash as $key=>$val) $aHash[$key] .= "a"; } print (microtime(true) - $t); ?> 

Если вы посмотрите на исходный код тестов: http://www.phpbench.com/source/test2/1/ и http://www.phpbench.com/source/test2/3/ , вы можете увидеть, что $ После каждой итерации aHash не возвращается в исходные данные. Он создается один раз в начале, затем каждый тест запускается X раз. В этом смысле вы работаете с постоянно растущим $ aHash для каждой итерации … в psuedocode:

 iteration 1: $aHash[10000000000000]=='aaaaaa....10000 times...a'; iteration 2: $aHash[10000000000000]=='aaaaaa....10001 times...a'; iteration 2: $aHash[10000000000000]=='aaaaaa....10002 times...a'; 

Со временем данные для всех тестов становятся больше для каждой итерации, поэтому, конечно, с помощью итерации 100, метод array_keys выполняется быстрее, потому что он всегда будет иметь те же ключи , где, поскольку цикл foreach должен конкурировать с постоянно растущим набор данных и сохранение значений в массивах!

Если вы запустите мой код, приведенный выше на вашем сервере, вы увидите, что foreach быстрее и более ясный и понятнее.

Если автор сайта предполагал, что его тест выполняет то, что он делает, то это, конечно, не ясно, и в противном случае это недействительный тест.

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