ID:               43568
 Updated by:       [EMAIL PROTECTED]
 Reported By:      gabriel at oxeva dot fr
-Status:           Open
+Status:           Closed
 Bug Type:         MySQLi related
 Operating System: Linux 2.6
 PHP Version:      5.3CVS-2007-12-11 (snap)
 New Comment:

This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

As Ulf (uw) said above: mysqli_stmt_bind_param() expects the parameters
to be references.It worked (more or less) by accident in previous
versions. But Dmitry now added a Warning so it won't fail silently; with
a current snapshot you'll get a error like "Warning: Parameter 1 to
mysqli_stmt::bind_param() expected to be a reference, value give in
...". see eyitsjunk at gmail dot com's comment to see how you can set
the references right.


Previous Comments:
------------------------------------------------------------------------

[2008-01-05 15:54:31] gabriel at oxeva dot fr

It's been a long time I haven't seen dynamic variables ($$var) in PHP
code. I consider that such language constructs are what make PHP code
sometime very unreadable, and creates very hard-to-find bugs. Nice
workaround though :-)

And you're right, the binding scenario is totally illogical and
inflexible. I think the normal scenario is creating the variables (or an
array of constant variables such as "array('abc', '3, 'test')", and then
binding these with the prepared statement, but not like in the
bind_param doc example which does a binding with auto-created variables,
then assigns them some data. Besides, using undefined variables in a
function call causes PHP  to throw a Notice in E_ALL error mode, doesn't
it? (Maybe it's different with references, but undocumented)

Note this is not the first time I see some very strange PHP behavior
when using references (PHP-like pointers), not to mention how hard it is
to do debugging with them.

Or maybe I'm completely wrong in the way I write my own PHP code
logic?

Anyway, I'm a bit out of this bug report's context. We still have a bug
in the way call_user_func_array returns functions passing variables by
reference.

------------------------------------------------------------------------

[2008-01-05 07:47:28] heyitsjunk at gmail dot com

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
=)

------------------------------------------------------------------------

[2008-01-04 18:00:37] [EMAIL PROTECTED]

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.

------------------------------------------------------------------------

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

Reply via email to