Domanda

Mi sono imbattuto in quello che sembra essere un problema con ambito variabile che non avevo mai riscontrato prima.Sto utilizzando il modulo CGI di Perl e una chiamata al metodo do() di DBI.Ecco la struttura del codice, leggermente semplificata:

use DBI;
use CGI qw(:cgi-lib);
&ReadParse;
my $dbh = DBI->connect(...............);
my $test = $in{test};
$dbh->do(qq{INSERT INTO events VALUES (?,?,?)},undef,$in{test},"$in{test}",$test);

La variabile segnaposto n. 1 viene valutata come se non fosse inizializzata.Le altre due variabili segnaposto funzionano.

La domanda:Perché l'hash %in non è disponibile nel contesto di do(), a meno che non lo racchiuda tra virgolette doppie (segnaposto n. 2) o riassegni il valore a una nuova variabile (segnaposto n. 3)?

Penso che abbia qualcosa a che fare con il modo in cui la funzione ReadParse() del modulo CGI assegna l'ambito all'hash %in, ma non conosco l'ambito Perl abbastanza bene per capire perché %in è disponibile al livello più alto ma non dal mio dominio () dichiarazione.

Se qualcuno capisce il problema dell'ambito, esiste un modo migliore per gestirlo?Racchiudere tutti i riferimenti %in tra virgolette doppie sembra un po' complicato.La creazione di nuove variabili per ogni parametro di query non è realistica.

Giusto per essere chiari, la mia domanda riguarda la questione dell'ambito variabile.Mi rendo conto che ReadParse() non è il metodo consigliato per acquisire i parametri di query con CGI.

Utilizzo Perl 5.8.8, CGI 3.20 e DBI 1.52.Grazie in anticipo a chiunque legga questo.

@Pi e @Bob, grazie per i suggerimenti.Predichiarare l'ambito per %in non ha alcun effetto (e utilizzo sempre strict).Il risultato è lo stesso di prima:nel db, col1 è null mentre cols 2 e 3 sono impostati sul valore previsto.

Per riferimento, ecco la funzione ReadParse (vedi sotto).È una funzione standard che fa parte di CGI.pm.Per come lo capisco, non intendo inizializzare l'hash %in (a parte soddisfare il rigoroso) ai fini dell'impostazione dell'ambito, poiché mi sembra che la funzione lo gestisca:

sub ReadParse {
    local(*in);
    if (@_) {
      *in = $_[0];
    } else {
    my $pkg = caller();
      *in=*{"${pkg}::in"};
    }
    tie(%in,CGI);
    return scalar(keys %in);
}

Immagino che la mia domanda sia: qual è il modo migliore per ottenere l'hash %in nel contesto di do()?Grazie ancora!Spero che questo sia il modo giusto per fornire ulteriori informazioni alla mia domanda originale.

@Dan:Ti ho sentito riguardo alla sintassi di &ReadParse.Normalmente utilizzerei CGI::ReadParse() ma in questo caso ho pensato che fosse meglio attenersi a come la documentazione CGI.pm ce l'ha esattamente.

È stato utile?

Soluzione

Secondo la documentazione DBI:L'associazione di una variabile legata non funziona, al momento.

DBI è piuttosto complicato sotto il cofano e sfortunatamente subisce alcuni cambiamenti per essere efficiente che causano il tuo problema.Sono d'accordo con tutti gli altri che dicono di sbarazzarsi del vecchio e brutto codice in stile cgi-lib.È già abbastanza spiacevole realizzare CGI senza una bella struttura (vai Catalyst), per non parlare di qualcosa che è obsoleto da un decennio.

Altri suggerimenti

In realtà non sembra che tu lo stia utilizzando come descritto nei documenti:https://metacpan.org/pod/CGI#COMPATIBILITY-WITH-CGI-LIB.PL

Se devi usarlo, allora CGI::ReadParse();sembra una sintassi più sensata e meno complicata.Anche se non riesco a vedere che faccia molta differenza in questa situazione, ma poi è una variabile legata, quindi chi diavolo sa cosa sta facendo ;)

C'è un motivo particolare per cui non puoi utilizzare la più comune sintassi $cgi->param('foo')?È un po' più pulito e sporca il tuo spazio dei nomi in un modo considerevolmente più prevedibile.

use strict;.Sempre.

Prova a dichiarare

our %in;

e vedere se questo aiuta.In mancanza di ciò, strict potrebbe produrre un errore più utile.

Non so cosa c'è che non va, ma posso dirti alcune cose che non lo sono:

  • Non è una questione di ambito.Se lo fosse, allora nessuno dei casi di $in{test} funzionerebbe.
  • Non è l'arcaico & sintassi chiamante.(Non è "giusto" ma in questo caso è innocuo.)

ReadParse è un brutto pezzo di codice.Elimina la tabella dei simboli per creare la variabile globale %in nel pacchetto chiamante.Quel che è peggio è che è una variabile legata, quindi accedervi potrebbe (teoricamente) fare qualsiasi cosa.Guardando il codice sorgente di CGI.pm, il file FETCH il metodo invoca semplicemente il metodo params() metodo per ottenere i dati.Non ho idea del motivo per cui il recupero nel file $dbh->do() non funziona.

In primo luogo, ciò non rientra nel contesto/ambito di azione.È ancora nel contesto principale o globale.Non lasci il contesto finché non inserisci {} in qualche modo correlato a subroutine o diverse 'classi' in perl.All'interno di () parentesi non stai lasciando l'ambito.

Il campione che ci hai fornito riguarda un hash non inizializzato e, come suggerito da Pi, l'utilizzo di strict eviterà sicuramente che ciò si verifichi.

Puoi darci un esempio più rappresentativo del tuo codice?Dove stai impostando %IN e come?

C'è qualcosa di molto rotto lì.L'ambito di Perl è relativamente semplice ed è improbabile che ti imbatti in qualcosa di strano del genere a meno che tu non stia facendo qualcosa di stupido.Come è stato suggerito, attivate il pragma rigoroso (e anche gli avvertimenti).In effetti dovresti usarli entrambi comunque).

È piuttosto difficile capire cosa sta succedendo senza poter vedere come è definito %in (ha qualcosa a che fare con quella chiamata ReadParse dall'aspetto sgradevole?perché lo chiami con la & iniziale, tra l'altro?quella sintassi è stata considerata morta e sepolta da molto tempo).Suggerisco di pubblicare un po' più di codice, così possiamo vedere cosa sta succedendo..

Che versione di DBI stai utilizzando?Dal guardare il Registro delle modifiche DBI sembra che le versioni precedenti alla 1.00 non supportassero l'argomento attributo.Ho il sospetto che il "non inizializzato" $in{test} è in realtà il undef verso cui stai passando $dbh->do().

Dall'esempio che hai fatto, questo è non un problema di ambito, altrimenti nessuno dei parametri funzionerebbe.

Sembra che DBI (o un DBD, non sono sicuro di dove vengano utilizzati i parametri di collegamento) non stia onorando la magia del legame.La soluzione alternativa sarebbe stringere o copiare ciò che gli passi, come fanno il tuo secondo e terzo parametro.

Un semplice test utilizzando SQLite e DBI 1.53 mostra che funziona correttamente:

$ perl -MDBI -we'sub TIEHASH { bless {} } sub FETCH { "42" } tie %x, "main" or die; my $dbh = DBI->connect("dbi:SQLite:dbname=dbfile","",""); $dbh->do("create table foo (bar char(80))"); $dbh->do("insert into foo values (?)", undef, $x{foo}); print "got: " . $dbh->selectrow_array("select bar from foo") . "\n"; $dbh->do("drop table foo")'
got: 42

Vuoi condividere il database che stai utilizzando?

Ok, prova questo:

use CGI;
my %in;
CGI::ReadParse(\%in);

Ciò potrebbe essere d'aiuto poiché in realtà utilizza una variabile che hai dichiarato e quindi può controllarne l'ambito (inoltre ti consentirà use strict senza altre cattiverie che potrebbero confondere le acque)

Poiché questo sta iniziando a sembrare un tie() problema, prova il seguente esperimento.Salvalo come foo.pl ed eseguilo come perl foo.pl "x=1"

use CGI;

CGI::ReadParse();
p($in{x}, "$in{x}");

sub p { my @a = @_; print "@a\n" }

Dovrebbe essere stampato 1 1.Se così non fosse, abbiamo trovato il colpevole.

Ho appena provato il tuo codice di prova da http://www.carcomplaints.com/test/test.pl.txt, e funziona subito sul mio computer, senza problemi.Ottengo tre valori come previsto.Non l'ho eseguito come CGI, ma usando:

...
use CGI qw/-debug/;
...

Scrivo una variabile sulla console (test=test) e gli script vengono inseriti senza problemi.

Se tuttavia lo lasci fuori, tt inserirà una stringa vuota e due NULL.Questo perché interpoli un valore in una stringa.Ciò creerà una stringa con valore di $in{test} che è undef al momento. undef stringifica in una stringa vuota, che è ciò che viene inserito nel database.

Prova questo

%in = LeggiParse();

ma ne dubito.Stai cercando di ottenere parametri di query o qualcosa del genere?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top