Блог → PHP: правильный перебор массивов

Довольно часто, в учебной литературе для перебора массивов предлагают следующую конструкцию:


$array = range(0, 999999);
$time_start = microtime(TRUE);
for($i=0; $i<count($array); $i++){}
echo microtime(TRUE)-$time_start;	

На первый взгляд все хорошо, но использовать такой код крайне не желательно. Дело в том, что на каждой итерации цикла, а если говорить точнее, при проверке условия, будет вызываться функция count(). Можно конечно видоизменить код следуюшим образом:


$array = range(0, 999999);
$time_start = microtime(TRUE);
for($i=0, $arr_l=count($array); $i<$arr_l; $i++){}
echo microtime(TRUE)-$time_start;	

Второй вариант будет работать быстрее. В моем случае разница составила 0.3 секунды. Но опять же получается как-то некрасиво, с дополнительной переменной, что не есть хорошо. Спрашивается, зачем вообще использовать цикл for, если в php существует замечательный цикл foreach? Который, кстати, специально предназначен для перебора массивов и объектов.


$array = range(0, 999999);
$time_start = microtime(TRUE);
foreach($array as $e){}
echo microtime(TRUE)-$time_start;

К тому же последний вариант, работает еще немного быстрее, чем предыдущий. Не значительно, но быстрее где-то на 0.01 секунды.

Так почему, некоторые, до сих пор продолжают использовать цикл for? Скорее всего дело в том, что неопытные программисты тут же зададут вопрос: "Мужик! Это конечно хорошо, но в последнем случае мы не можем изменять элементы массива". И опять же, это является очень большим заблуждением. Рассмотрим простой пример, переберем все элементы масива и умножим их на 2. Пожалуйста:


$array = range(0, 999999);
$time_start = microtime(TRUE);
foreach($array as &$e){
	$e *= 2;
}
unset($e);
echo microtime(TRUE)-$time_start;

Здесь разница состоит лишь в том, что переменная $e будет являться ссылкой на значение элемента массива. Ну и не забываем удалять ее после выполнения цикла с помощью функции unset(). Делать это нужно обязательно. Почитайте здесь.

И напоследок, еще один пример, где действительно может пригодится конструкция for. Здесь речь идет о случае, когда нужно перебрать элементы массива с конца. И опять, многие источники предлагают делать так:


$array = range(0, 999999);
$time_start = microtime(TRUE);
for(end($array); $k=current($array); prev($array)){
	$array[$k] *= 2;
}
echo microtime(TRUE)-$time_start;

Хотя можно просто, без наворотов:


$array = range(0, 999999);
$time_start = microtime(TRUE);
for($i=count($array); $i>=0; $i--){
	$array[$i] *= 2;
}
echo microtime(TRUE)-$time_start;

Время выполнения первого скрипта 0.856 сек, второго — 0.157 сек (быстрее в 5 раз!). Какой из них лучше решать вам.


Комментарии (6)

MuFF
Первый раз увидел что можно изменять массив в foreach'е: foreach($array as &$e) $e *= 2; Всегда делал так: foreach($array as $k => $e) $array[$k] *= 2; Вот так - век живи, век учись )
Ответить
korolariya
Пожалуй добавлю блог в избранные
Ответить
Антон
Как работать с двухмерными и трехмерными массивами в цикле foreach?
Ответить
Иван
Очень просто, так же как и с двухмерными, можно проверять что приходит при каждой итерации цикла. Пример рекурсия

$users = [ 'administration' => [ 'ivan', 'egor', 'sub_administration' => [ 'sVetLana', 'AlEX' ] ], 'engine' => [ 'Alex', 'DmitRiy', ] ]; function unsetUser($name = '',array &$users){ foreach ($users as $key => &$user) { if(is_array($user)) unsetUser($name,$user); else if(mb_strtolower($user)==mb_strtolower($name)) unset($users[$key]); } } unsetUser('svetlana',$users); var_dump($users);
Ответить
Alex
Смотря для чего применять. Если для одномерного массива второй и третий вариант примерно одинаковые по скорости, то для перебора каких-нибудь объектов, записей БД дублирование массива приведёт к заметному отставанию foreach.
Ответить
Игорь
Во всех тестах говорится, что for быстрее foreach, а у вас наоборот) http://php.spb.ru/php/speed.html
Ответить


Оставить свой комментарий


Представтесь, пожалуйста *

Ваш комментарий

Число на картинке *

captcha

На хостинг