#43568 [Com]: mysqli statement stmt->bind_param doesn't work when called by call_user_func

From: Date: Sat, 05 Jan 2008 07:47:28 +0000
Subject: #43568 [Com]: mysqli statement stmt->bind_param doesn't work when called by call_user_func
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-121055@lists.php.net to get a copy of this message
ID: 43568 Comment by: heyitsjunk at gmail dot com Reported By: gabriel at oxeva dot fr Status: Open Bug Type: MySQLi related Operating System: Linux 2.6 PHP Version: 5.3CVS-2007-12-11 (snap) New Comment: Gabriel you don't need to use eval() to solve this issue.. I'll try to explain by making your first example work the way you're thinking. I changed some variable names for convenience but it's the same example. $my = new mysqli('localhost', 'test', 'test', 'testdb'); $stmt = $my->prepare('INSERT INTO car (brand, brand_id, car_type) VALUES (?, ?, ?)'); $params = array('sss', 'GMC', 1, 'SUV'); //Okay I'll assume that the above is what I have to work with. $types = $params[0]; unset($param[0]); $i = 0; foreach ($params as $param) { $bind_name = 'bind' . $i; $$bind_name = $param; $bind_names[] = &$$bind_name; } $bind_params[] = $types; $bind_params[] = array_merge($bind_params, $bind_names) //Added code ends here. $return = call_user_func_array(array($stmt, 'bind_param'), $bind_params); var_dump($return); $stmt->execute(); echo $stmt->errno, ':', $stmt->error; So now you got yourself a working code. With the same method of binding, you can make yourself the ultimate lazy query function that handles this situation: $params = array('sss', 'GMC', 1, 'SUV'); query('INSERT INTO car (brand, brand_id, car_type) VALUES (?, ?, ?)', $params); or this is my preference but it doesn't handle BLOB types: query('INSERT INTO car (brand, brand_id, car_type) VALUES (?, ?, ?)', $brand, $brand_id, $car_type); Anyways my point is I do agree with this logic though the doc explanation "call_user_func_array" is MISLEADING. I couldn't figure it out until I saw uw.php.net's examples. The whole binding scenario is pretty tough and inflexible. Still needs to be looked over by an expert =) Previous Comments: ------------------------------------------------------------------------ [2008-01-04 18:00:37] uw@php.net I suggest that we leave the bug status as is for the moment. From what I know some PHP hackers are already discussing the case and Johannes (Schlüter) will take care that it does not get forgotten. Your comment on the example in the documentation is welcome. I agree with you that, for example, a code comment might be help beginners understand the example better. The manual example works because PHP implicitly creates a variable for you whenever you start to use one. There's no need in PHP to sort of declare a variable before you use it. So, on the one hand it might make sense to change the example like this: $bind_param = null; mysqli_stmt_bind_param(..., &$bind_param) ... on the other hand, there's no need for the assignment operation. Its a PHP feature that you can start using variables ad-hoc and PHP does all the magic for you behind the scenes to make this possible. In that sense the extra line is nothing but overhead. A beginner might appreciate to see the line '$bind_param = null' before the call to mysqli_stmt_bind_param() to sort of better visualize the "pass by reference" requirement but an experienced PHP hacker might remove the line from the code because its not needed. Maybe the bottom line is to write even more "verbose" examples? ------------------------------------------------------------------------ [2008-01-04 17:20:09] gabriel at oxeva dot fr It seems you posted your comment before I finished writing mine. Good to see that I'm not going crazy because I just tested the case with sort and got the same bug as you! Should I change the category for this bug? If so, which one? ------------------------------------------------------------------------ [2008-01-04 14:53:32] gabriel at oxeva dot fr I understand now why this isn't supposed to work, but it is with PHP 5.2 This "new" behavior make this bind_param function a lot less attractive when using it in situations like ZF does: binding an unknown number of parameters to a statement (like in any Object-Relational Mapper). There is no way now other than using the very ugly eval() to dynamically create the required number of variables to bind with bind_param. Besides, this method is never suppposed to return NULL, (doc says boolean return, TRUE on success, FALSE on failure). This is why I almost immediately thought that was a bug. Another fact is the doc example is very strange with calling stmt_bind_param with variables _before_ having them created. This is very "special" coding style. My final thought: The old behavior (PHP 5.2) is really useful because there is no other way to do the same with the new one except using eval() as an ugly workaround, and the new behavior is returning an undocumented (and useless) value. I really don't know if I have to file a new bug report in 5_2 about the incorrect behavior of bind_param (which is IMHO the most useful one). Thank you anyway for the explanation, I'm now waiting for the final opinions about this. ------------------------------------------------------------------------ [2008-01-04 14:30:39] uw@php.net Hold on, a PHP internals expert should have a look. sort() is another example of a function which uses pass by reference. The manual says about call_user_func_array(): "Note: Referenced variables in param_arr are passed to the function by a reference, others are passed by a value. In other words, it does not depend on the function signature whether the parameter is passed by a value or by a reference. " From a discussion with Johannes: sapi/cli/php -r '$a = array(2, 1); var_dump(call_user_func_array("sort", array($a)));' PHP 5.2 -> bool(true) PHP 5.3 -> NULL Looks like its not a mysqli issue but rather a general PHP issue. ------------------------------------------------------------------------ [2008-01-04 13:49:02] uw@php.net Forgot to say: IMHO this should be reported over at Zend Framework but not here. I've tested 5_2, 5_3, 6_0 and I see no differences in handling. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/43568 -- Edit this bug report at http://bugs.php.net/?id=43568&edit=1

« previous php.bugs (#121055) next »