2010-04-26 13 views
7

Ho utilizzato PDO e preparato tutte le mie istruzioni principalmente per motivi di sicurezza. Tuttavia, ho una parte del mio codice che fa esegue la stessa istruzione molte volte con parametri diversi, e ho pensato che sarebbe stato dove le dichiarazioni preparate brillavano davvero. Ma in realtà infrangono il codice ...Ricorsione in istruzioni preparate

La logica di base del codice è questa.

function someFunction($something) { 
    global $pdo; 

    $array = array(); 

    static $handle = null; 
    if (!$handle) { 
    $handle = $pdo->prepare("A STATEMENT WITH :a_param"); 
    } 

    $handle->bindValue(":a_param", $something); 
    if ($handle->execute()) { 
    while ($row = $handle->fetch()) { 
     $array[] = someFunction($row['blah']); 
    } 
    } 

    return $array; 
} 

Mi sembrava soddisfacente, ma mancava un sacco di file. Alla fine mi sono reso conto che l'handle dell'istruzione veniva modificato (eseguito con parametri diversi), il che significa che la chiamata per il recupero del ciclo while funzionerà solo una volta, quindi la funzione si chiama nuovamente e il set di risultati viene modificato.

Quindi mi chiedo quale sia il modo migliore di utilizzare le istruzioni PDO preparate in modo ricorsivo.

Un modo potrebbe essere utilizzare fetchAll(), ma nel manuale si dice che ha un notevole overhead. Il punto centrale di tutto ciò è renderlo più efficiente.

L'altra cosa che potrei fare non è riutilizzare un handle statico, e invece ne fare uno nuovo ogni volta. Credo che poiché la stringa di query è la stessa, internamente il driver MySQL utilizzerà comunque una dichiarazione preparata, quindi c'è solo il piccolo sovraccarico di creare un nuovo handle su ogni chiamata ricorsiva. Personalmente penso che sconfigga il punto.

Oppure c'è un modo per riscriverlo?

+0

ho solo fatto qualche (non super scientifico) testare il mio codice funzione ricorsivo molto simile e avere conc Ho lodato che per i miei scopi, le dichiarazioni preparate sono complessivamente più lente. Qual è il punto di preparare una dichiarazione se devi ri-prepararla prima di ogni utilizzo? Devo mancare qualcosa. –

risposta

2

Non è possibile nidificare le maniglie dell'istruzione: è necessario chiudere l'handle precedentemente aperto prima di aprirne un altro all'interno di una singola sessione.

Infatti, PDO fa automaticamente quando si emette una nuova preparazione.

Quando si chiama la funzione in modo ricorsivo:

  • La maniglia iniziale è allocata (1)
  • Il primo record è inverosimile di (1)
  • La funzione viene chiamata in modo ricorsivo. Il valore di (1) risiede nello stack di ricorsione.
  • La nuova maniglia è allocato (2), invalidando (1)
  • Il primo record è inverosimile di (2)
  • La funzione restituisce
  • Si tenta di prendere il prossimo record di (1) e non riescono dal momento che è valida

Detto questo, MySQL non supporta la ricorsione su un lato e ciò significa che dovrai farlo sul lato PHP, utilizzando fetchAll.

+0

A quale maniglia ti riferisci? Puoi avere molti handle di istruzioni preparati all'interno di una singola sessione (credo che ci sia un limite di circa 500 istruzioni preparate lato server per sessione e un totale di istruzioni 'max_prepared_stmt_count', ma questo non si applica alle istruzioni preparate create usando la libreria lato client). I risultati non hanno la loro maniglia. – outis

0

Il vero problema è che $handle è statico. Le variabili statiche sono problematiche per la ricorsione quando lo stato deve essere preservato attraverso una chiamata ricorsiva, non solo per le istruzioni preparate. In questo caso, la chiamata ricorsiva esegue una nuova query, scartando lo stato precedente. PDO::fetchAll è infatti l'unica opzione se si desidera una singola query preparata.

A seconda di quale sia l'affermazione, è possibile riscriverlo potenzialmente per restituire tutti i risultati contemporaneamente, creando successivamente l'albero.

+0

@outis: '$ handle' è statico per un motivo: può esserci solo una istruzione attiva all'interno di una sessione. – Quassnoi

+0

@Quassnoi: mi rendo conto che c'è un motivo per cui '$ handle' è statico. Tuttavia, le variabili statiche semplicemente non funzionano nel modo in cui Rob le vuole in chiamate ricorsive. – outis

+0

@Quassnoi: e cosa intendi per "attivo"? Ci possono essere molte dichiarazioni preparate all'interno di una singola sessione, anche se ognuna conterrà un solo set di risultati. – outis

0

Se si utilizzano le stesse variabili, (a causa del valore pdo bindValue) ogni valore temporale è uguale al primo. Quindi questo fallirà:

foreach ($bind_params as $key => $value) { 
    $stmt->bindParam(":$key", $value); 
} 

risultato:

$key[0] = $value[0]; 
$key[1] = $value[0]; 
$key[2] = $value[0]; 
$key[3] = $value[0]; 

Così si vuole fare brutta trucco, quindi:

 $i = 0; 
     foreach ($bind_params as $key => $value) { 
      $i++; 
      $$i = $value; 
      $stmt->bindParam(":$key", $$i); 
     } 

risultato:

$key[0] = $value[0]; 
$key[1] = $value[1]; 
$key[2] = $value[2]; 
$key[3] = $value[3]; 
Problemi correlati