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;

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).


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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.