Zugriff auf externe Variablen mit anonymer Funktion als Parameter

93

Grundsätzlich verwende ich diese praktische Funktion zum Verarbeiten von Datenbankzeilen (ein Auge auf PDO und / oder andere Dinge werfen)

function fetch($query,$func) {
    $query = mysql_query($query);   
    while($r = mysql_fetch_assoc($query)) {
        $func($r);
    }
}

Mit dieser Funktion kann ich einfach:

fetch("SELECT title FROM tbl", function($r){
   //> $r['title'] contains the title
});

Nehmen wir jetzt an, ich muss alles $r['title']in einem var verketten (dies ist nur ein Beispiel).

Wie könnte ich das machen? Ich habe so etwas gedacht, aber es ist nicht sehr elegant:

$result = '';
fetch("SELECT title FROM tbl", function($r){
   global $result;
   $result .= $r['title'];
});

echo $result;
dynamisch
quelle

Antworten:

188

Sie müssen usewie in den Dokumenten beschrieben verwenden :

Abschlüsse können auch Variablen vom übergeordneten Bereich erben. Solche Variablen müssen im Funktionsheader deklariert werden. Das Erben von Variablen aus dem übergeordneten Bereich ist nicht dasselbe wie das Verwenden globaler Variablen. Globale Variablen existieren im globalen Bereich, der unabhängig von der ausgeführten Funktion gleich ist.

Code:

$result = '';
fetch("SELECT title FROM tbl", function($r) use (&$result) {
   $result .= $r['title'];
});

Aber Vorsicht (entnommen aus einem der Kommentare im vorherigen Link):

use () -Parameter sind frühe Bindungen - sie verwenden den Wert der Variablen an dem Punkt, an dem die Lambda-Funktion deklariert wird, und nicht an dem Punkt, an dem die Lambda-Funktion aufgerufen wird (späte Bindung).

Xaerxess
quelle
1
Sollte diese globale Verzögerung nicht beseitigt werden?
Aziz Punjani
19
+1 für die Hervorhebung der early binding. Wie auch immer, im obigen Beispiel use (&$result)ist es nicht wirklich wichtig, wann als Referenz übergeben wird?
Dimitry K
4
@DimitryK Ja, hier wird die Referenz verwendet, um das Standardverhalten zu umgehen (frühe Bindung).
Xaerxess
3
@machineaddict Die Grundvoraussetzung use ist die frühe Bindung - wenn Sie eine Problemumgehung für die späte Bindung meinen - würden Sie die Variable als useReferenz übergeben - mit &=> use (&$result)und die $resultVariable ändern , bevor Sie die anonyme Funktion (oder etwas, das sie aufruft)
aufrufen
1
Da Klasseninstanzen immer als Referenz übergeben werden, müssen Sie & nicht für sie verwenden. (es sei denn, Sie überschreiben die Instanz vollständig).
Joel Harkes
0

Was ist mit dem Umschreiben von 'fetch', um $ func nur einmal aufzurufen?

function fetch($query,$func) {
    $query = mysql_query($query);   
    $retVal = array();
    while($r = mysql_fetch_assoc($query)) {
        $retVal[] = $r;
    }
    $func($retVal);
}

Auf diese Weise würden Sie $ func nur einmal aufrufen und das einmal abgerufene Array erneut verarbeiten? Ich bin mir nicht sicher über die Leistung, obwohl das 200-fache Aufrufen einer Funktion keine gute Idee ist.

user103307
quelle
Ja, du hast recht. Sie können jedoch mysql_fetch_row () anstelle von mysql_fetch_assoc () verwenden, wenn Sie hier und da ein paar ms gewinnen möchten. Es ist einfach furchtbar schwierig, damit umzugehen, da Sie die Position Ihrer Spalten kennen müssen. Auf diese Weise übergeben Sie bei 2000 Anforderungen mit jeweils 30 Zeilen von 0,205 auf 0,180.
user103307