PHP PDOStatement: Analysis of data insertion errors in bindParam

  • 2020-11-26 18:43:57
  • OfStack

Without further ado, just look at the code:

<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', "test");

$query = <<<QUERY
  INSERT INTO `user` (`username`, `password`) VALUES (:username, :password);
QUERY;
$statement = $dbh->prepare($query);

$bind_params = array(':username' => "laruence", ':password' => "weibo");
foreach( $bind_params as $key => $value ){
    $statement->bindParam($key, $value);
}
$statement->execute();

What is the final SQL statement executed and is there anything wrong with the above code?
Okey, I think most of the students will think that the final SQL is:
INSERT INTO `user` (`username`, `password`) VALUES ("laruence", "weibo");
Unfortunately, you are wrong. SQL is:
INSERT INTO `user` (`username`, `password`) VALUES ("weibo", "weibo");
Is it a big hole?
This question comes from today's 1 Bug report: #63281
The reason is the difference between bindParam and bindValue. bindParam requires the second parameter to be a reference variable (reference).
Let's break down foreach in the above code, which is this foreach:

<?php
foreach( $bind_params as $key => $value ){
    $statement->bindParam($key, $value);
}

Is equivalent to:

<?php
// The first 1 loops 
$value = $bind_params[":username"];
$statement->bindParam(":username", &$value); // At this time , :username Is the $value Reference to a variable 

// The first 2 loops 
$value = $bind_params[":password"]; //oops! $value Covered with :password The value of the 
$statement->bindParam(":password", &$value);

Therefore, when using bindParam, pay particular attention to the trap used in conjunction with foreach. So what's the right approach?
1. Do not use foreach, but manually assign values

<?php
$statement->bindParam(":username", $bind_params[":username"]); //$value It's a reference variable 
$statement->bindParam(":password", $bind_params[":password"]);

2. Use bindValue instead of bindParam, or pass the entire parameter array directly in execute.
3. Use foreach and reference(not recommended)

<?php
foreach( $bind_params as $key => &$value ) { // Note that there 
    $statement->bindParam($key, $value);
}

Finally, it is expanded that foreach should be used with caution when using functions that require a reference and have a lag processing.

Related articles: