107

Basically I use this handy function to processing db rows (close an eye on PDO and/or other stuff)

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

With this function I can simply do:

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

Let's say now I need to concatenate all $r['title'] in a var (this is just an example).

How could I do that? I was thinking something like this, but it's not very elegant:

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

echo $result;
dynamic
  • 46,985
  • 55
  • 154
  • 231
  • Same technique on an earlier asked question: [How to increment count in the replacement string when using preg_replace?](https://stackoverflow.com/q/2184601/2943403) – mickmackusa Mar 25 '23 at 07:13

2 Answers2

211

You have to use use as described in docs:

Closures may also inherit variables from the parent scope. Any such variables must be declared in the function header. Inheriting variables from the parent scope is not the same as using global variables. Global variables exist in the global scope, which is the same no matter what function is executing.

Code:

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

But beware (taken from one of comments in previous link):

use() parameters are early binding - they use the variable's value at the point where the lambda function is declared, rather than the point where the lambda function is called (late binding).

Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
  • 1
    Shouldn't that global deceleration be removed ? – aziz punjani Dec 06 '11 at 17:19
  • 20
    +1 for emphasizing the `early binding`. However I guess in the example above when `use (&$result)` is passed by reference it doesn't really matter? – Dimitry K Jun 19 '14 at 12:13
  • 4
    @DimitryK Yes, reference is used here to bypass default behaviour (early binding). – Grzegorz Rożniecki Jun 19 '14 at 15:42
  • Thanks so very much. I have been digging all around to do somethign that in JavaScript would have been obvious. – AturSams Oct 13 '14 at 08:34
  • @Xaerxess: is there a workaround for the `early binding` of `use`? – machineaddict Dec 17 '14 at 12:35
  • 3
    @machineaddict The basic `use` **is** early binding - if you mean workaround for late binding - you would pass the variable through `use` by reference - using `&` => `use (&$result)` and alter `$result` variable before you call the anonymous function (or something, that calls it) – jave.web Mar 13 '16 at 14:14
  • 1
    Since class instances are always passed by reference you wont need to use & for them. (unless you completely overwrite the instance). – Joel Harkes Jul 24 '18 at 05:04
  • For JS people: early binding means lexical scope (just like in a JS closure) while late binding means dynamic scope. – totymedli Mar 05 '20 at 17:13
0

What about rewriting 'fetch' to call $func only once ?

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

This way you would call $func only once and re-process the array once fetched? Not sure about the performance even tho calling 200 times a function doesn't sound like a good idea.

user103307
  • 19
  • 1
  • Yes you are right. However, you could use mysql_fetch_row() instead of mysql_fetch_assoc() if you're that interested in gaining a few ms here and there... it's just awfully hard to deal with as you'd have to know your columns position. By doing so, you pass from 0.205 to 0.180 on 2000 requests of 30 rows each. – user103307 Dec 06 '11 at 17:56