2

I was reading the PHP manual for mysqli_stmt_bind_result and saw this code in the comments:

while ( $field = $meta->fetch_field() ) {
  $parameters[] = &$row[$field->name];
}

given that neither $params nor $row existed before that line, why/how does that line work?

1
  • Sorry, I linked to the wrong wrong manual page. Links are fixed now Commented Apr 22, 2011 at 14:04

4 Answers 4

6

PHP doesn't actually have variable declaration. That means in some cases you can reference variables without actually having them declared beforehand. I say some cases because:

foreach($undefinedArray as $key=>$value){
    // will give a notice and a warning
    // notice: undefined variable
    // warning: invalid argument to foreach
}

But this doesn't mean you can't do something like so:

for($i=0;$i<5;$i++){
    $undefinedArray[]=$i;
}
// will create an array with 5 indexes, each holding the numbers 0 through 4

This works because $undefinedArray is not found and created on the fly.

Now, regarding your own case. I'm gonna assume you mean this post. And I have to admit, that's a very interesting solution, I'm gonna try to restrain myself from commenting on any kind of bad practice there, but let's get on to explaining it!

$params[] = &$row[$field->name]; 

This is where the magic happens and it's actually due to the &. Because &$row['unknown_index'], actually creates the index!

This means that above statement does 2 things. First it creates an array with each column name saved as an index in $row ($row[$field->name]). Then it saves a pointer to each of the elements from $row in $params.

call_user_func_array(array($stmt, 'bind_result'), $params); 

This does $stmt->bind_result(). But passes each of the elements in $params as parameters to bind_result. And since they're passed by reference, each index of $row will hold each of the selected fields.

The rest should be easy to figure out now.

If you got any questions. Feel free to ask!

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! But why does the author create 2 arrays there? Wouldn't just doing $row[$field->name] suffice? (Actually I meant de2.php.net/manual/en/mysqli-stmt.bind-param.php#100879 (didn't know I could diretly link to comments), but they're the same code...)
Because he wants to use call_user_func_array which passes each index of the array as parameters to the function. It's just easier to pass a non-fixed number of parameters via that function and he also needs each index to be a variable that won't clash (namely $row). Hard to explain in this comment. If you still don't get it, I'll reconsider updating my post :)
Yes, I understand why call_user_func_array() is being used. But what do you mean by clash?
I'm referring to the scope of variables, just having $row[$field->name] can clash with other variables in the same scope.
4

From the first comment.

    $variables = array();
    $data = array();
    $meta = $result->result_metadata();

    while($field = $meta->fetch_field())
        $variables[] = &$data[$field->name]; // pass by reference

    call_user_func_array(array($result, 'bind_result'), $variables);

So what's the problem?

1 Comment

You are looking at the wrong comment. Sorry I didn't link to it in the first place. In the comment I meant $data didn't exist before calling it in the loop.
1

It won't work because as you said, these variables do not exist.

Comments

1

Being from C,C++ school of programming, i sometimes struggle to come to terms with PHP's stack and heap management. PHP does way too many things automatically, which gives way too much freedom to developers. Anyways, am sure Dexter has got his doubts cleared after that wonderful explanation from Khez. I just want to add my cents in the code to make more sense of whats happening in the code mentioned here.

$stmt = $conn->prepare ("SELECT * FROM sample");
$stmt->execute ();
$meta = $stmt->result_metadata();

$params  = array (); // You can skip these lines, PHP initiates arrays on
$row     = array (); // the fly. I prefer doing as much of these initializations
$results = array (); // as possible, on my own.

while ($field = $meta->fetch_field())
{
    /* Again, you can skip the following line, PHP will automatically create
     * a new key/value pair and since we are using the same name for the
     * container of that key/value pair, PHP will actually keep appending. 
     * So after N loops you have an array that contains N key/value pairs
     */
    $row [$field->name] = 0;

    $params[] =& $row[$field->name];
}

/* So now, $params is an array of N references, where reference i points to 
 * the value part of i-th key/val pair in $row 
 */

call_user_func_array (array ($stmt, 'bind_result'), $params);
$index = 0;
while ($stmt->fetch ())
{
    // again, one can skip this. PHP creates this on the fly.
    $results[$index] = array();
    foreach ($row as $key => $val)
    {
        // skip making that temp array!
        $results[$index][$key] = $val;
    }

    $index += 1;
}

return $results;

So that's it. Hopefully this code will make sense.

P.S: As an afterthought, I want to clarify one of my doubts regarding PHP. If I try to populate $results as below:

$results[$index][] = $row;

Or like this:

$results[] = $row;

All sets of key/value pairs in $results contain the same set repeatedly. Hopefully somebody and throw some light on this behavior of PHP.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.