PHP + MYSQLI: Variable parameter/result binding wi

2019-01-22 00:59发布

问题:

In a project that I'm about to wrap up, I've written and implemented an object-relational mapping solution for PHP. Before the doubters and dreamers cry out "how on earth?", relax -- I haven't found a way to make late static binding work -- I'm just working around it in the best way that I possibly can.

Anyway, I'm not currently using prepared statements for querying, because I couldn't come up with a way to pass a variable number of arguments to the bind_params() or bind_result() methods.

Why do I need to support a variable number of arguments, you ask? Because the superclass of my models (think of my solution as a hacked-up PHP ActiveRecord wannabe) is where the querying is defined, and so the find() method, for example, doesn't know how many parameters it would need to bind.

Now, I've already thought of building an argument list and passing a string to eval(), but I don't like that solution very much -- I'd rather just implement my own security checks and pass on statements.

Does anyone have any suggestions (or success stories) about how to get this done? If you can help me solve this first problem, perhaps we can tackle binding the result set (something I suspect will be more difficult, or at least more resource-intensive if it involves an initial query to determine table structure).

回答1:

In PHP you can pass a variable number of arguments to a function or method by using call_user_func_array. An example for a method would be:

call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);

The function will be called with each member in the array passed as its own argument.



回答2:

You've got to make sure that $array_of_params is array of links to variables, not values themselves. Should be:

$array_of_params[0] = &$param_string; //link to variable that stores types

And then...

$param_string .= "i";
$user_id_var = $_GET['user_id'];//
$array_of_params[] = &$user_id_var; //link to variable that stores value

Otherwise (if it is array of values) you'll get:

PHP Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference


One more example:

$bind_names[] = implode($types); //putting types of parameters in a string
for ($i = 0; $i < count($params); $i++)
{
   $bind_name = 'bind'.$i; //generate a name for variable bind1, bind2, bind3...
   $$bind_name = $params[$i]; //create a variable with this name and put value in it
   $bind_names[] = & $$bind_name; //put a link to this variable in array
}

and BOOOOOM:

call_user_func_array( array ($stmt, 'bind_param'), $bind_names); 


回答3:

I am not allowed to edit, but I believe in the code

call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);

The reference in front of $stmt is not necessary. Since $stmt is the object and bindparams is the method in that object, the reference is not necessary. It should be:

call_user_func_array(array($stmt, 'bindparams'), $array_of_params);

For more information, see the PHP manual on Callback Functions."



回答4:

call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);

Didn't work for me in my environment but this answer set me on the right track. What actually worked was:

$sitesql = '';
$array_of_params = array();
foreach($_POST['multiselect'] as $value){
    if($sitesql!=''){
        $sitesql .= "OR siteID=? ";
        $array_of_params[0] .= 'i';
        $array_of_params[] = $value;
    }else{
        $sitesql = " siteID=? ";
        $array_of_params[0] .= 'i';
        $array_of_params[] = $value;
    }
}

$stmt = $linki->prepare("SELECT IFNULL(SUM(hours),0) FROM table WHERE ".$sitesql." AND week!='0000-00-00'");
call_user_func_array(array(&$stmt, 'bind_param'), $array_of_params);
$stmt->execute();