Это немного странно, и я вполне мог кодировать это совершенно неправильно - поэтому я дважды за два дня столкнулся с одной и той же ошибкой в совершенно разных частях скрипта. Код, который я использую, приведен ниже:
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);
}
}
Я новичок в использовании PDO, но в основном я пытаюсь передать массив ограничений, например.
array( 'active' => 1, 'name' => 'James' ) and return all rows from the table WHERE active = 1 AND name = 'James'Если я использую этот массив, SQL выполняется с первого
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.
Если я передаю массив с одним ограничением, например
array( 'active' => 1 ), this works perfectly fine. It appears to be whenever multiple constraints are passed that it stops working.






Это потому, что bindParam работает путем привязки к переменной, и вы повторно используете переменную ($value) для нескольких значений. Попробуйте вместо этого использовать bindValue.
Или еще лучше; Вместо этого передайте значения в виде массива в execute. Это делает оператор не имеющим состояния, что обычно хорошо в программировании.
Как уже упоминалось, использование bindValue вместо bindParam, безусловно, позволит добиться этого. Однако, потратив в последнее время значительное количество времени на устранение этой проблемы, я обнаружил альтернативное решение. Вот как выполнить привязку переменной PDO в цикле foreach с помощью bindParam:
Замените следующую строку из исходного сообщения:
$PDOStatement->bindParam( $field, $value );
...с этим:
$PDOStatement->bindParam( $field, $constraints[$field] );
Вместо привязки $value используйте $array_name[$array_key]. Это работает, потому что теперь вы привязываетесь к уникальной переменной, а не к той, которая повторно используется на каждом проходе цикла.
Однако переменная $field, используемая в качестве заполнителя, не обязательно должна быть уникальной. Я еще не исследовал это полностью, но переменная, используемая в качестве заполнителя, кажется, сразу анализируется (вместо того, чтобы назначаться в качестве ссылки на переменную), даже когда используется bindParam.
Кроме того, поскольку вам больше не потребуется напрямую обращаться к $value, вы также можете заменить это:
foreach( $constraints as $field => $value ) {
... с этим:
foreach (array_keys($constraints) as $field) {
Это необязательно, так как без этого изменения он будет работать нормально. На мой взгляд, он выглядит чище, так как позже может возникнуть путаница, почему $value назначается, но никогда не используется.