Недавно читал заметку одного опытного прогера про то, что он давно уже избавился от конструкций типа if, foreach, заменив первый на тернарный оператор, а последний на array_map/array_walk. Плюс ещё какие-то приёмы. Ну прочитал и забыл. А сейчас решил освежить память и никак не могу вспомнить, где читал. То ли на медиуме, то ли на freeCodeCamp'е. Но не суть. Озадачился я вопросом быстродействия этих решений.

Сравнивать if с тернарным оператором особо не имеет смысла, а вот приём с array_map решил проверить. Написал простенький тест. Результат получился неожиданным — foreach на порядок быстрее array_map. Картина маслом. Проверял я на PHP 7. На пятёрке не вижу смысла это делать.

Ради интереса решил протестировать основные конструкции цикла. Причем варианты array_map и array_walk вызываются в двух вариантах — с анонимной фукнцией и обычной (объявленной). Для большей наглядности я взял массив из миллиона элементов.

<?php

$numbers = 1000000;
$items = range(0, $numbers);

#1 Foreach
$tstart= microtime(true);
$result = [];
foreach ($items as $item) {
    $result[] = $item * 10;
}
echo number_format(microtime(true) - $tstart, 10), ": foreach", "<br>";

#2 For
$tstart= microtime(true);
$result = [];
for ($i=0; $i<=$numbers; $i++) {
    $result[] = $items[$i] * 10;
}
echo number_format(microtime(true) - $tstart, 10), ": for" ,"<br>";

#3 While
$tstart= microtime(true);
$result = [];
while ($numbers >= 0) {
    $result[] = $items[$numbers] * 10;
    $numbers--;
}
echo number_format(microtime(true) - $tstart, 10), ": while" ,"<br>";

#4 array_map (usual function)
$tstart= microtime(true);
function multi10($number) {
    return $number * 10;
}
$result = array_map('multi10', $items);
echo number_format(microtime(true) - $tstart, 10), ": array_map (обычная функция)", "<br>";

#5 array_map (lambda function)
$tstart= microtime(true);
$result = array_map(function($number) {
    return $number * 10;
}, $items);
echo number_format(microtime(true) - $tstart, 10), ": array_map (анонимная функция)", "<br>";

#6 array_walk (usual function)
$tstart= microtime(true);
$result = array_walk($items, 'multi10');
echo number_format(microtime(true) - $tstart, 10), ": array_walk (обычная функция)", "<br>";

#7  array_walk (lambda function)
$items = range(0, $numbers);
$tstart= microtime(true);
$result = array_walk($items, function($number) {
    return $number * 10;
});
echo number_format(microtime(true) - $tstart, 10), ": array_walk (анонимная функция)", "<br>";

И вот какой результат:

0.2690150738: foreach
0.3570210934: for
0.3400189877: while
0.8420479298: array_map (обычная функция)
1.8021039963: array_map (анонимная функция)
0.8600490093: array_walk (обычная функция)
1.8251039982: array_walk (анонимная функция)

В общем, вывод напрашивается сам собой — доверяй, но проверяй. foreach оказался самым быстрым и отказываться от него было бы глупо. Хотя в своё время читал, что for самый пресамый.

Лично моё мнение, использовать array_map нужно только при оправданной необходимости. Кстати, обратите внимание на то, что обработка анонимной функции отнимает в 2 раза больше времени, чем обработка обычной функции.

П.С. У кого есть возможность запустить тест на PHP 5.x, выложите в комментариях.

Update 22.08.2018

Запустил данный скрипт на modhost.pro. Всё-таки окружение на локалке отличается от реального на сайте. Количество итераций снижено до 1000 из-за ограничений памяти на тестовом сайте.

0.0000169277: foreach
0.0000212193: for
0.0000209808: while
0.0000278950: array_map (обычная функция)
0.0000321865: array_map (анонимная функция)
0.0000429153: array_walk (обычная функция)
0.0000419617: array_walk (анонимная функция)

Как видите, разница получилась не такая уж и большая, но всё равно foreach не сдал позиции.

16 августа 2018, 10:24   145     0

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

    Вы должны авторизоваться, чтобы оставлять комментарии.

    Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.