Hi! I have a problem with binding parameters dynamically in my mysqli_stmt objects. As I don't know how many parameters which will be put into this function I must bind the parameters dynamically. Though I cannot understand what's wrong with this method:

public function execute($unprp_stmt, $data){
   //Prepare the stmt
   $stmt = $this->con->prepare($unprp_stmt);
   //Get dynamically built parameter string for the bind_param method. E.g. 'issis'
   $paramstr = $this->get_paramstr($data);
            
   // Dynamically build up the arguments for bind_param
   $params = array();
   array_unshift($params, $stmt, $data, $paramstr);
   print_r($params);
   // and then call bind_param with the proper arguments
   call_user_func_array('mysqli_stmt_bind_param', $params);
}

Out of this I get the following error:

Output of print_r:
Array ( [0] => mysqli_stmt Object ( [affected_rows] => -1 [insert_id] => 0 [num_rows] => 0 [param_count] => 1 [field_count] => 6 [errno] => 0 [error] => [sqlstate] => 00000 [id] => 1 ) [1] => i [2] => 1 ) 

And the following error:
[B]Warning:[/B] Parameter 3 to mysqli_stmt_bind_param() expected to be a reference, value given in C:\xampp\htdocs\HTSIBWORT\gw_fetcher.php on line 27

as we can see in the output from print_r is the value of parameter 3 = 1.

Why doesn't this work? Please help me out!

Dani AI

Generated

Short answer: the warning means mysqli_stmt_bind_param needs real variables (passed by reference), and your call_user_func_array is handing values, not references. In your Post #1 you pushed the whole data/value as a single array element and call_user_func_array forwarded that value — PHP then fails because bind_param expects parameter 3+ to be references.

A small, reliable fix is to build an argument array where each bound value is a reference, then call the object's bind_param via call_user_func_array. The helper below shows the idea (it is different from the examples already posted):

function refValues($arr) {
    $refs = array();
    foreach ($arr as $k => $v) {
        $refs[$k] = &$arr[$k];
    }
    return $refs;
}

/* usage: $types is like "iss" and $values is an indexed array of variables */
$params = array_merge(array($types), $values);
call_user_func_array(array($stmt, 'bind_param'), refValues($params));

Notes and troubleshooting:

  • : the function in Post #2 is nearly there — the missing piece is converting the values into references before calling call_user_func_array.
  • Make sure the types string length equals the number of variables you bind. Bind only real variables (not literals or expressions).
  • If you prefer another approach, invoking bind_param with ReflectionMethod->invokeArgs or manually assigning variables then calling bind_param is also used, but converting to an array of references is simplest and widely compatible.
  • If problems persist, var_dump the types string, count($values) and $stmt->param_count to confirm they match, and ensure you’re calling the object method (array($stmt,'bind_param')) rather than the procedural function with the wrong argument order.

Could someone please help me by examining closely how these methods work? I found them when trying to solve this problem:

(original post)
http://stackoverflow.com/questions/1384191/how-to-make-a-proper-mysqli-extension-class-with-prepared-statements

Assuming you're actually wanting to write your own version (as opposed to utilizing one of the existing libraries other answers have suggested - and those are good options, too)...

Here are a couple of functions which you may find it useful to examine. The first allows you to bind the results of a query to an associative array, and the second allows you to pass in two arrays, one an ordered array of keys and the other an associative array of data for those keys and have that data bound into a prepared statement:

function stmt_bind_assoc (&$stmt, &$out) {
    $data = mysqli_stmt_result_metadata($stmt);
    $fields = array();
    $out = array();

    $fields[0] = $stmt;
    $count = 1;

    while($field = mysqli_fetch_field($data)) {
        $fields[$count] = &$out[$field->name];
        $count++;
    }
    call_user_func_array(mysqli_stmt_bind_result, $fields);
}

function stmt_bind_params($stmt, $fields, $data) {
    // Dynamically build up the arguments for bind_param
    $paramstr = '';
    $params = array();
    foreach($fields as $key)
    {
        if(is_float($data[$key]))
            $paramstr .= 'd';
        elseif(is_int($data[$key]))
            $paramstr .= 'i';
        else
            $paramstr .= 's';
        $params[] = $data[$key];
    }
    array_unshift($params, $stmt, $paramstr);
    // and then call bind_param with the proper arguments
    call_user_func_array('mysqli_stmt_bind_param', $params);
}

What I don't get is what the first class is doing. How do I utilize the result from it?

Btw, I found a solution to the earlier problem in the comments on this page:
http://www.n8williams.com/devblog/php/prepared-statement-errors-with-php-5-3-and-mysqli-call_user_func_array-returns-null

seriously, not a single answer?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.