2016-05-03 4 views
2

Я работаю над решением «Очень большой суммы» на HackerRank. Цель состоит в том, чтобы получить сумму всех элементов в массиве без использования array_sum. Для ясности мой примерный код здесь немного отличается от кода.PHP Обратные функции и переменные ссылки

Это работает:

$arr = array( 
    1000000001, 
    1000000002, 
    1000000003, 
    1000000004, 
    1000000005 
); 

$total = 0; 
array_walk($arr, 'totalize'); 
echo '*' . $total; 

function totalize($arr_item) { 
    global $total; 
    $total += $arr_item; 
} 

Я хотел бы избежать использования глобальной, так что я могу делать вещи правильно при использовании функции обратного вызова в будущем. Однако это не работает. Я покажу вывод после кода:

$arr = array( 
    1000000001, 
    1000000002, 
    1000000003, 
    1000000004, 
    1000000005 
); 

$total = 0; 
array_walk($arr, 'totalize', $total); 
echo '*' . $total; 

function totalize($arr_item, $key, &$total) { 
    $total += $arr_item; 
    echo $arr_item . '.' . $key . '.' . $total . '<br />'; 
} 

Это дает это как выход:

1000000001.0.1000000001 
1000000002.1.2000000003 
1000000003.2.3000000006 
1000000004.3.4000000010 
1000000005.4.5000000015 
*0 

Почему $ общее добавляются правильно, но затем получает брошенный?

Ответ: Благодаря @ miken32 я обнаружил, что это работает:

$arr = array( 
    1000000001, 
    1000000002, 
    1000000003, 
    1000000004, 
    1000000005 
); 

$total = 0; 
array_walk($arr, function($arr_item) use (&$total) { totalize($arr_item, $total); }); 
echo '*' . $total; 

function totalize($arr_item, &$total) { 
    $total += $arr_item; 
    echo $arr_item . '.' . $total . '<br />'; 
} 

Это дает этот выход:

1000000001.1000000001 
1000000002.2000000003 
1000000003.3000000006 
1000000004.4000000010 
1000000005.5000000015 
*5000000015 
+0

Использовать анонимную функцию и использовать 'use()' или просто сделать простой цикл foreach, чтобы пройти через ваш массив и суммировать значения вместе. – Rizier123

+0

Как связаны пространства имен? Я пытаюсь научиться передавать указатель на функцию, а не только решить эту проблему. – Cyrcle

+0

Не 'use', а' use() 'для анонимных функций, есть разница :) – Rizier123

ответ

3

Для данного конкретного случая вы можете использовать anonymous function с the use keyword для импорта $total в область действия функции.

$arr = [ 
    1000000001, 
    1000000002, 
    1000000003, 
    1000000004, 
    1000000005 
]; 

$total = 0; 
array_walk($arr, function ($arr_item) use (&$total) {$total += $arr_item;}); 
echo '*' . $total; 
+0

Спасибо, я смог пропустить анонимную функцию по ссылке на функцию сумматора. Я бы показал код, но он не форматирует красиво в комментариях. Я исправлю, что обратные вызовы не могут проходить по ссылке без использования анонимной функции? – Cyrcle

+0

Если функция обратного вызова 'array_walk()' была настроена для принятия переменной по ссылке, нет причин, по которой она не будет работать. Но это похоже на попытку заставить любую встроенную функцию принимать значение по ссылке. Если это не так, как было написано, это не сработает. – miken32

2

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

Но нет никакой связи между глобальной переменной $total и переменной, переданной вашему обратному вызову (аргумент $total из totalize()). Вы можете это увидеть сами, если вы измените totalize(), чтобы отобразить значение глобальной переменной $total.

Более подходящий способ для достижения вашей цели - использовать array_reduce(). Первый пример в документации - это точно решение вашей проблемы.

+0

Обратный вызов действительно передает ссылку. Ядро PHP изменилось в том, как они обрабатывают обратные вызовы, передающие ссылки. Использование: array_walk ($ arr, 'totalize', & $ total); дает ошибку: Неустранимая ошибка: переадресация вызова по ссылке была удалена в /home/quicksil/public_html/test.php в строке 12 – Cyrcle

+0

Действительно, вы не можете принудительно передать глобальную '$ total' в качестве ссылки на 'array_walk()'. Он копирует значение, которое он получает в качестве третьего аргумента, и не меняет его. Вы можете даже передать '0' в качестве третьего аргумента, и он все равно дает тот же результат. – axiac

Смежные вопросы