Это немного странно, и я вполне мог бы кодировать это совершенно неправильно – поэтому почему я дважды попадал в ту же ошибку дважды за два дня в совершенно разных частях сценария. Код, который я использую, приведен ниже:
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' )
и вернуть все строки из таблицы
WHERE active = 1 AND name = 'James'
Если я использую этот массив, SQL выполняется с первого
var_dump( )
является
SELECT * FROM {table} WHERE active = :active AND name = 'James'
– точно так, как я ожидаю. Связанные параметры печатают «Binding active to 1» и «Binding name to James» – точно так, как ожидалось. Строки существуют в базе данных, и все же вторая
var_dump()
вызов для $ results не выводит ничего, т. е. строки не возвращаются.
Если я передаю массив одного ограничения, например
array( 'active' => 1 )
, это работает отлично. Кажется, что когда передаются несколько ограничений, они перестают работать.
Это потому, что bindParam
работает привязкой к переменной, и вы повторно используете переменную ( $value
) для нескольких значений. bindValue
этого bindValue
вместо 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
назначено, но никогда не используется.