Accéder à une variable extérieure en utilisant une fonction anonyme comme paramètres

93

En gros, j'utilise cette fonction pratique pour traiter les lignes de base de données (fermez un œil sur PDO et / ou d'autres choses)

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

Avec cette fonction, je peux simplement faire:

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

Disons maintenant que j'ai besoin de tout concaténer $r['title']dans un var (ce n'est qu'un exemple).

Comment pourrais-je faire ça? Je pensais à quelque chose comme ça, mais ce n'est pas très élégant:

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

echo $result;
dynamique
la source

Réponses:

188

Vous devez utiliser usecomme décrit dans la documentation :

Les fermetures peuvent également hériter des variables de la portée parent. Toutes ces variables doivent être déclarées dans l'en-tête de la fonction. L'héritage de variables de la portée parent n'est pas la même chose que l'utilisation de variables globales. Les variables globales existent dans la portée globale, qui est la même quelle que soit la fonction en cours d'exécution.

Code:

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

Mais attention (extrait de l'un des commentaires du lien précédent):

Les paramètres use () sont une liaison précoce - ils utilisent la valeur de la variable au point où la fonction lambda est déclarée, plutôt qu'au point où la fonction lambda est appelée (liaison tardive).

Xaerxess
la source
1
Cette décélération globale ne devrait-elle pas être supprimée?
aziz punjani
19
+1 pour souligner le early binding. Cependant, je suppose que dans l'exemple ci-dessus, quand use (&$result)est passé par référence, cela n'a pas vraiment d'importance?
Dimitry K
4
@DimitryK Oui, la référence est utilisée ici pour contourner le comportement par défaut (liaison anticipée).
Xaerxess
3
@machineaddict La base use est une liaison anticipée - si vous voulez dire une solution de contournement pour une liaison tardive - vous passeriez la variable usepar référence - en utilisant &=> use (&$result)et en modifiant la $resultvariable avant d'appeler la fonction anonyme (ou quelque chose qui l'appelle)
jave.web
1
Puisque les instances de classe sont toujours passées par référence, vous n'aurez pas besoin d'utiliser & pour elles. (sauf si vous écrasez complètement l'instance).
Joel Harkes
0

Pourquoi ne pas réécrire «fetch» ​​pour appeler $ func une seule fois?

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

De cette façon, vous n'appeleriez $ func qu'une seule fois et re-traiteriez le tableau une fois extrait? Pas sûr de la performance même si appeler 200 fois une fonction ne semble pas être une bonne idée.

user103307
la source
Oui, tu as raison. Cependant, vous pouvez utiliser mysql_fetch_row () à la place de mysql_fetch_assoc () si vous êtes intéressé à gagner quelques ms ici et là ... c'est vraiment difficile à gérer car vous devez connaître la position de vos colonnes. Ce faisant, vous passez de 0,205 à 0,180 sur 2000 requêtes de 30 lignes chacune.
user103307