Dostęp do zmiennej zewnętrznej przy użyciu funkcji anonimowej jako parametrów

94

Zasadniczo używam tej przydatnej funkcji do przetwarzania wierszy db (zwróć uwagę na PDO i / lub inne rzeczy)

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

Dzięki tej funkcji mogę po prostu:

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

Powiedzmy, że teraz muszę połączyć wszystko $r['title']w zmiennej (to tylko przykład).

Jak mogłem to zrobić? Myślałem o czymś takim, ale nie jest to zbyt eleganckie:

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

echo $result;
dynamiczny
źródło

Odpowiedzi:

190

Musisz używać usezgodnie z opisem w dokumentach :

Zamknięcia mogą również dziedziczyć zmienne z zakresu nadrzędnego. Wszelkie takie zmienne muszą być zadeklarowane w nagłówku funkcji. Dziedziczenie zmiennych z zakresu nadrzędnego to nie to samo, co używanie zmiennych globalnych. Zmienne globalne istnieją w zasięgu globalnym, który jest taki sam niezależnie od wykonywanej funkcji.

Kod:

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

Ale uwaga (zaczerpnięte z jednego z komentarzy w poprzednim linku):

Parametry use () są wczesnym wiązaniem - używają wartości zmiennej w punkcie, w którym deklarowana jest funkcja lambda, a nie w punkcie, w którym funkcja lambda jest wywoływana (późne wiązanie).

Xaerxess
źródło
1
Czy nie powinno się usunąć tego globalnego spowolnienia?
aziz punjani
19
+1 za podkreślenie early binding. Jednak myślę, że w powyższym przykładzie, kiedy use (&$result)jest przekazywany przez odniesienie, to tak naprawdę nie ma znaczenia?
Dimitry K
4
@DimitryK Tak, odwołanie jest tutaj używane do obejścia domyślnego zachowania (wczesne wiązanie).
Xaerxess
3
@machineaddict Podstawą use jest wczesne wiązanie - jeśli masz na myśli obejście dla późnego wiązania - przekażesz zmienną useprzez odniesienie - używając &=> use (&$result)i zmień $resultzmienną przed wywołaniem funkcji anonimowej (lub czegoś, co ją wywołuje)
jave.web
1
Ponieważ instancje klas są zawsze przekazywane przez referencje, nie musisz używać dla nich &. (chyba że całkowicie nadpisujesz instancję).
Joel Harkes
0

A co z przepisaniem „fetch”, aby wywołać $ func tylko raz?

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

W ten sposób wywołałbyś $ func tylko raz i ponownie przetworzyłbyś tablicę po pobraniu? Nie jestem pewien co do wydajności, nawet jeśli wywołanie funkcji 200 razy nie wydaje się dobrym pomysłem.

user103307
źródło
Tak masz rację. Możesz jednak użyć mysql_fetch_row () zamiast mysql_fetch_assoc (), jeśli jesteś zainteresowany uzyskaniem kilku ms tu i tam ... jest to po prostu strasznie trudne, ponieważ musisz znać pozycję swoich kolumn. W ten sposób przechodzisz od 0,205 do 0,180 w 2000 żądaniach po 30 wierszy każdy.
user103307