@Snewer

Чем array_walk лучше foreach?

Здравствуйте!

Всегда, когда нужно было применить что-либо к каждому элементу массива пользовался конструкцией foreach ($array as &$item), но наличие специальной функции array_walk не давало покоя.

На досуге решил протестировать оба варианта:
1. с циклом:
$t = microtime(true);
$array = array_fill(0, 1000000, 'hello world');

foreach ($array as &$item) {
    $item = 'hello!';
}

echo microtime(true) - $t;
echo '<br>';
echo memory_get_usage();

2. array_walk:
$t = microtime(true);
$array = array_fill(0, 1000000, 'hello world');

array_walk($array, function(&$item){
    $item = 'hello!';
});

echo microtime(true) - $t;
echo '<br>';
echo memory_get_usage();


Получились такие результаты для миллиона элементов:
100304928 байт и 0,33 секунды для foreach и 100305424 байт и 0,86 секунды для array_walk
То есть циклом оказалось еще и более, чем в два раза быстрее.

Что можете сказать по этому поводу?
Для чего было вводить функцию array_walk, уступающую языковым конструкциям?

p.s. спортивный интерес.
  • Вопрос задан
  • 4760 просмотров
Решения вопроса 2
webinar
@webinar Куратор тега PHP
Учим yii: https://youtu.be/-WRMlGHLgRg
Сделайте тоже самое, только запихните не $item = 'hello!'; а что-то посложнее и разница будет меньше.
Ну и банально избежать дублирование кода.
function test_print($item2, $key) 
{
    echo "$key. $item2<br />\n";
}
array_walk($array1, 'test_print');
array_walk($array2, 'test_print');
array_walk($array3, 'test_print');
array_walk($array4, 'test_print');
array_walk($array5, 'test_print');
//вот тебе новая выгода:
$func_name = 'test_print';
array_walk($array5, $func_name);

Прикиньте это c foreach

В целом foreach и if else творят чудеса и позволяют сделать что угодно. А порой это даже быстрее работает. Но выглядит не читабельно, по сути не гибко и т.д.
Ответ написан
Комментировать
@novrm
Работая по ссылке с foreach можете налететь на очень неприятны грабли, которые незаметны и сильно попортят вам нервы.
Особенно когда разработчики неопытные.
И именно - ссылку после foreach нужно удалять.
array_walk для работы по ссылке - само-то, лишь тем и лучше.
В других случаях — будь попроще — используй foreach.

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

Пример:
array_walk($guide['postInGuides'], function (&$postInGuide, $key) use ($guide, $viewRenderer) {
    $postInGuide['post']['url'] = [
        'read' => $viewRenderer->url('guide/guide/post', [
            'slugGuide' => $guide['name'],
            'slugPost'  => $postInGuide['post']['slug'],
        ]),
        'update' => $viewRenderer->url('post/post/action', [
            'slugPost'  => $postInGuide['post']['slug'],
            'action' => 'update',
        ]),
        'delete' => $viewRenderer->url('post/post/action', [
            'slugPost'  => $postInGuide['post']['slug'],
            'action' => 'delete',
        ]),
    ];
});
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
GavriKos
@GavriKos
Не знаток именно PHP. Но как минимум отличие в том, что во втором случае вызывается функция при каждой итерации цикла. На вызов функции тоже тратится время.
Ответ написан
@t3946
array_walk позволяет записать обход массива в одну строку, также позволяет указывать тип в callback'е, что удобно для объектов
Ответ написан
Комментировать
Maksclub
@Maksclub Куратор тега PHP
maksfedorov.ru
Если сама функция array_walk может быть не интересной, то ее рекурсивная версия куда вкуснее, тк работает с вложенными массивами
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы