Доступ к внешней переменной с использованием анонимной функции в качестве параметров

94

В основном я использую эту удобную функцию для обработки строк db (закройте глаза на PDO и / или другие вещи)

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

С помощью этой функции я могу просто:

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

Скажем, теперь мне нужно объединить все $r['title']в var (это всего лишь пример).

Как я мог это сделать? Я думал примерно так, но это не очень элегантно:

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

echo $result;
динамичный
источник

Ответы:

190

Вы должны использовать, useкак описано в документации :

Замыкания также могут наследовать переменные из родительской области. Любые такие переменные должны быть объявлены в заголовке функции. Наследование переменных из родительской области - это не то же самое, что использование глобальных переменных. Глобальные переменные существуют в глобальной области видимости, которая остается неизменной независимо от того, какая функция выполняется.

Код:

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

Но будьте осторожны (взято из одного из комментариев в предыдущей ссылке):

Параметры use () являются ранним связыванием - они используют значение переменной в точке, где объявлена ​​лямбда-функция, а не в точке, где вызывается лямбда-функция (позднее связывание).

Xaerxess
источник
1
Не следует ли убрать это глобальное замедление?
азиз пунджани 06
19
+1 за подчеркивание early binding. Однако я предполагаю, что в приведенном выше примере, когда use (&$result)передается по ссылке, это не имеет значения?
Dimitry K
4
@DimitryK Да, здесь используется ссылка для обхода поведения по умолчанию (раннее связывание).
Xaerxess
3
@machineaddict Основным use является раннее связывание - если вы имеете в виду обходной путь для позднего связывания - вы должны передать переменную useпо ссылке - используя &=> use (&$result)и изменить $resultпеременную, прежде чем вызывать анонимную функцию (или что-то, что ее вызывает)
jave.web
1
Поскольку экземпляры классов всегда передаются по ссылке, вам не нужно использовать для них &. (если вы полностью не перезаписываете экземпляр).
Joel Harkes
0

Как насчет того, чтобы переписать "fetch" так, чтобы $ func вызывалась только один раз?

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

Таким образом, вы вызываете $ func только один раз и повторно обрабатываете массив после получения? Не уверен в производительности, даже если вызывать функцию 200 раз - это не очень хорошая идея.

user103307
источник
Да ты прав. Однако вы можете использовать mysql_fetch_row () вместо mysql_fetch_assoc (), если вам интересно получить несколько мс тут и там ... с этим просто ужасно трудно справиться, так как вам нужно знать положение своих столбцов. Таким образом вы перейдете от 0,205 к 0,180 для 2000 запросов по 30 строк в каждом.
user103307 06