Reputation: 1002
This is a bit of a weird one, and I could well be coding this completely wrong - hence why I've hit the same error twice in two days, in completely different parts of a script. The code I'm using is below:
public function findAll( $constraints = array() ) {
// Select all records
$SQL = 'SELECT * FROM ' . $this->tableName;
// See if there's any constraints
if( count( $constraints ) > 0 ) {
$SQL .= ' WHERE ';
foreach( $constraints as $field => $value ) {
$SQL .= $field . ' = :' . $field . ' AND ';
}
}
// Remove the final AND and prepare the statement
$SQL = substr( $SQL, 0, -5 );
$PDOStatement = $this->PDO->prepare( $SQL );
// Loop through constraints and bind parameters
foreach( $constraints as $field => $value ) {
print 'Binding ' . $field . ' to ' . $value . '
';
$PDOStatement->bindParam( $field, $value );
}
$PDOStatement->execute();
var_dump($PDOStatement);
while ( $results = $PDOStatement->fetch( PDO::FETCH_ASSOC ) ) {
var_dump($results);
}
}
I'm pretty new to using PDO, but basically I'm attempting to pass an array of constraints e.g.
array( 'active' => 1, 'name' => 'James' )
and return all rows from the table WHERE active = 1 AND name = 'James'
If I use this array, the SQL executed from the first
var_dump( )
is SELECT * FROM {table} WHERE active = :active AND name = 'James'
- exactly as I expect. The bound parameters prints 'Binding active to 1' and 'Binding name to James' - exactly as expected. The rows exist in the database, and yet the second var_dump()
call for $results outputs nothing - i.e. no rows are returned.
If I pass an array of a single constraint, e.g.
array( 'active' => 1 )
, this works perfectly fine. It appears to be whenever multiple constraints are passed that it stops working.
Upvotes: 2
Views: 1535
Reputation: 1003
As mentioned, using bindValue
instead of bindParam
will certainly accomplish this. However, after spending a considerable amount of time troubleshooting this issue recently, I discovered an alternate solution. Here is how to accomplish PDO variable binding in a foreach loop using bindParam:
Replace the following line from the original post:
$PDOStatement->bindParam( $field, $value );
...with this:
$PDOStatement->bindParam( $field, $constraints[$field] );
Instead of binding $value
, use $array_name[$array_key]
. This works is because you are now binding to a unique variable instead of one that gets reused on each pass of the loop.
The variable $field
used as the placeholder apparently does not need to be a unique variable, however. I have not thoroughly researched this yet, but a variable used as a placeholder appears to be parsed immediately (instead of being assigned as a variable reference) even when bindParam is used.
Also, as you would no longer need to access $value
directly, you could also replace this:
foreach( $constraints as $field => $value ) {
... with this:
foreach (array_keys($constraints) as $field) {
This is optional, as it will work fine without this change. It looks cleaner in my opinion though, since it might get confusing later as to why $value
is assigned but never used.
Upvotes: 0
Reputation: 117567
That's because bindParam
works by binding to a variable, and you are re-using the variable ($value
) for multiple values. Try with bindValue
instead.
Or even better yet; Pass the values as an array to execute
instead. This makes the statement stateless, which is generally a good thing in programming.
Upvotes: 10