2016-05-03 7 views
2

Ich arbeite an der Lösung "A Very Big Sum" auf HackerRank. Das Ziel besteht darin, die Summe aller Elemente in einem Array zu erzeugen, ohne array_sum zu verwenden. Aus Gründen der Klarheit ist mein Beispielcode hier ein wenig anders als der Code dort.PHP Callback Funktionen und Variablenreferenzen

Dies funktioniert:

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

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

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

Ich möchte eine globale vermeiden, mit so kann ich die Dinge richtig tun, wenn in Zukunft Callback-Funktionen verwenden. Dies funktioniert jedoch nicht. Ich werde den Ausgang nach dem Code zeigen:

$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 />'; 
} 

Es gibt diese als Ausgabe:

1000000001.0.1000000001 
1000000002.1.2000000003 
1000000003.2.3000000006 
1000000004.3.4000000010 
1000000005.4.5000000015 
*0 

Warum der Gesamt $ korrekt hinzugefügt bekommen, aber dann aufgegeben wird?

Antwort: Dank @ miken32 fand ich, dass dies funktioniert:

$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 />'; 
} 

Es gibt diese Ausgabe:

1000000001.1000000001 
1000000002.2000000003 
1000000003.3000000006 
1000000004.4000000010 
1000000005.5000000015 
*5000000015 
+0

Verwenden Sie entweder eine anonyme Funktion und verwenden Sie 'use()' oder machen Sie einfach eine einfache foreach-Schleife, um durch Ihr Array zu gehen und die Werte zusammen zu addieren. – Rizier123

+0

Wie hängen Namespaces zusammen? Ich versuche zu lernen, einen Zeiger auf eine Funktion zu übergeben, nicht nur dieses Problem zu lösen. – Cyrcle

+0

Nicht 'use', aber' use() 'für anonyme Funktionen, gibt es einen Unterschied :) – Rizier123

Antwort

3

In diesem speziellen Fall können Sie anonymous function mit the use keyword verwenden, um $total in den Funktionsumfang zu importieren.

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

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

Danke, ich konnte die anonyme Funktion durch Verweis auf die Totalisatorfunktion übergeben lassen. Ich würde den Code anzeigen, aber er formatiert nicht gut in Kommentaren. Habe ich also Recht, dass Callbacks nicht ohne eine anonyme Funktion als Referenz weitergegeben werden können? – Cyrcle

+0

Wenn 'array_walk() '' s Callback-Funktion eingerichtet wurde, um eine Variable als Referenz zu akzeptieren, kein Grund, es würde nicht funktionieren. Aber es ist so, als würde man versuchen, eine eingebaute Funktion durch Verweis zu einem Wert zu machen. Wenn das nicht so geschrieben ist, wird es nicht funktionieren. – miken32

2

Das dritte Argument von array_walk() kann nicht als Referenz übergeben werden. Wenn Sie array_walk() aufrufen, verwendet es den Wert, den Sie als sein drittes Argument übergeben, um eine lokale Variable zu initialisieren. Dann übergibt es die lokale Variable anhand Ihres Callbacks (denn so ist Ihr Callback definiert).

Es gibt jedoch keine Verbindung zwischen der globalen Variablen $total und der Variablen, die an Ihren Callback übergeben wurde (das Argument $total von). Sie können dies selbst sehen, wenn Sie ändern, um auch den Wert der globalen Variablen $total anzuzeigen.

Eine geeignetere Methode, um Ihr Ziel zu erreichen, ist die Verwendung array_reduce(). Das erste Beispiel in der Dokumentation ist genau die Lösung für Ihr Problem.

+0

Der Rückruf gibt eine Referenz weiter. Der PHP-Kern hat sich in der Art und Weise geändert, wie Callbacks Referenzen verarbeiten. Verwendung: array_walk ($ arr, 'totalize', & $ total); gibt den Fehler: Schwerwiegender Fehler: Call-Time-Pass-by-Referenz wurde in /home/quicksil/public_html/test.php in Zeile 12 – Cyrcle

+0

entfernt In der Tat können Sie nicht erzwingen, die globale "$ total" als Referenz zu übergeben 'array_walk()'. Es kopiert den Wert, den es als drittes Argument erhält, es ändert es nicht. Sie können sogar "0" als drittes Argument übergeben und es wird immer noch das gleiche Ergebnis erzielt. – axiac