Errore con la sovrascrittura di bindParam in PHP
Domanda
Questo è un po 'strano, e potrei benissimo scrivere questo codice completamente sbagliato, quindi perché ho riscontrato lo stesso errore due volte in due giorni, in parti completamente diverse di uno script. Il codice che sto usando è sotto:
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);
}
}
Sono abbastanza nuovo nell'uso del PDO, ma fondamentalmente sto cercando di superare una serie di vincoli, ad es.
array( 'active' => 1, 'name' => 'James' )
e restituisce tutte le righe dalla tabella WHERE active = 1 AND name = 'James'
Se uso questo array, l'SQL eseguito dal primo
var_dump( )
è SELECT * FROM {table} WHERE active = :active AND name = 'James'
, esattamente come mi aspetto. I parametri associati stampano "Binding attivo su 1" e "Binding name to James", esattamente come previsto. Le righe esistono nel database, eppure la seconda chiamata var_dump()
per $ results non restituisce nulla, ovvero nessuna riga viene restituita.
Se passo una matrice di un singolo vincolo, ad es.
array( 'active' => 1 )
, funziona perfettamente. Sembra che ogni volta che vengono superati più vincoli smetta di funzionare.
Soluzione
Questo perché bindParam
funziona con associazione a una variabile e si sta riutilizzando la variabile ( $ value
) per più valori. Prova invece con bindValue
.
O ancora meglio; Passa i valori come matrice a esegui
anziché. Questo rende la dichiarazione apolide, che è generalmente una buona cosa in programmazione.
Altri suggerimenti
Come accennato, usando bindValue
invece di bindParam
riuscirà sicuramente a farlo. Tuttavia, dopo aver trascorso molto tempo a risolvere questo problema di recente, ho scoperto una soluzione alternativa. Ecco come realizzare l'associazione delle variabili PDO in un ciclo foreach utilizzando bindParam:
Sostituisci la seguente riga dal post originale:
$PDOStatement->bindParam( $field, $value );
... con questo:
$PDOStatement->bindParam( $field, $constraints[$field] );
Invece di associare $ value
, usa $ array_name [$ array_key]
. Questo funziona perché ora stai vincolando una variabile unica anziché una che viene riutilizzata ad ogni passaggio del ciclo.
Tuttavia, la variabile $ field
utilizzata come segnaposto non deve necessariamente essere una variabile univoca. Non l'ho ancora studiato a fondo, ma una variabile utilizzata come segnaposto sembra essere analizzata immediatamente (anziché essere assegnata come riferimento variabile) anche quando si utilizza bindParam.
Inoltre, poiché non avresti più bisogno di accedere direttamente a $ value
, puoi anche sostituire questo:
foreach( $constraints as $field => $value ) {
... con questo:
foreach (array_keys($constraints) as $field) {
Questo è facoltativo, poiché funzionerà bene senza questa modifica. A mio avviso, tuttavia, sembra più pulito, dal momento che potrebbe diventare più confuso in seguito al motivo per cui $ value
è assegnato ma mai utilizzato.