3

以前に遭遇したことのない可変スコープの問題と思われるものに遭遇しました。Perl の CGI モジュールと DBI の do() メソッドの呼び出しを使用しています。コード構造を少し簡略化したものを次に示します。

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);

#1 プレースホルダー変数は、初期化されていないかのように評価されます。他の 2 つのプレースホルダー変数は機能します。

質問: do() のコンテキスト内で %in ハッシュを使用できないのはなぜですか?二重引用符で囲む (#2 プレースホルダー) か、値を新しい変数に再割り当てする (#3 プレースホルダー) 場合を除きます。

CGI モジュールの ReadParse() 関数がスコープを %in ハッシュに割り当てる方法と関係があると思いますが、なぜ %in がトップレベルで利用可能であるのに私の do 内からは利用できないのかを理解するのに十分なほど Perl のスコーピングを知りません。 () 声明。

誰かがスコーピングの問題を理解している場合、それを処理するより良い方法はありますか? すべての %in 参照を二重引用符で囲むのは少し面倒です。クエリ パラメータごとに新しい変数を作成するのは現実的ではありません。

明確にするために、私の質問は変数のスコープの問題に関するものです。ReadParse() は、CGI でクエリ パラメータを取得するための推奨される方法ではないことに気付きました。

Perl 5.8.8、CGI 3.20、および DBI 1.52 を使用しています。これを読んでいる人に事前に感謝します。

@Pi & @Bob、提案をありがとう。%in のスコープを事前に宣言しても効果はありません (私は常に strict を使用しています)。結果は前と同じです。データベースでは、col1 は null ですが、cols 2 と 3 は期待値に設定されています。

参考までに、ReadParse 関数を次に示します (以下を参照)。CGI.pmの標準機能です。私が理解しているように、関数はそれを処理するように見えるので、スコープを設定する目的で %in ハッシュを初期化するつもりはありません (strict を満たす以外)。

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

私の質問は、do() のコンテキスト内で %in ハッシュを取得する最良の方法は何だと思いますか? 再度、感謝します!これが、元の質問に追加情報を提供する正しい方法であることを願っています。

@Dan: &ReadParse 構文について聞いたことがあります。通常は CGI::ReadParse() を使用しますが、この場合は、CGI.pm ドキュメントに正確に記載されている方法に固執するのが最善であると考えました。

4

12 に答える 12

4

ドキュメントで説明されているように、実際に使用しているようには見えません: https://metacpan.org/pod/CGI#COMPATIBILITY-WITH-CGI-LIB.PL

それを使用する必要がある場合は、CGI::ReadParse(); より賢明で、より粗雑な構文のようです。私はそれがこの状況で大きな違いを生んでいるのを見ることはできませんが、それは引き分けの変数なので、一体誰がそれが何をしているのかを知っています;)

より一般的な $cgi->param('foo') 構文を使用できない特別な理由はありますか? それは少しきれいで、かなり予測可能な方法で名前空間を汚します..

于 2008-09-18T02:19:09.327 に答える
3

use strict;. いつも。

宣言してみてください

our %in;

そして、それが役立つかどうかを確認します。これに失敗するとstrict、より有用なエラーが発生する可能性があります。

于 2008-09-18T01:48:10.370 に答える
3

何が問題なのかわかりませんが、そうでないことをいくつか教えてください。

  • それはスコープの問題ではありません。そうであれば、 のインスタンスはどれも機能しません$in{test}
  • 古風な&呼び出し構文ではありません。(「正しい」ではありませんが、この場合は無害です。)

ReadParse厄介なコードです。シンボル テーブルを変更して、呼び出し元のパッケージにグローバル変数 %in を作成します。さらに悪いことに、それは関連付けられた変数であるため、それにアクセスすると (理論的には) 何でもできてしまいます。CGI.pm のソース コードを見ると、FETCHメソッドはメソッドを呼び出しparams()てデータを取得するだけです。のフェッチが機能しない理由がわかり$dbh->do()ません。

于 2008-09-18T02:54:38.790 に答える
2

何かが非常に壊れています。Perl のスコーピングは比較的単純で、何か馬鹿げたことをしていない限り、そのような奇妙なことに出くわすことはまずありません。提案されているように、strict プラグマを有効にします (および警告も有効にします。実際には、とにかく両方を使用する必要があります)。

%in がどのように定義されているかを確認することができずに、何が起こっているかを伝えるのはかなり困難です (それは、その見苦しい ReadParse 呼び出しと関係がありますか? 先頭に & を付けて呼び出しているのはなぜですか? その構文は死んでいると見なされています)そして長い間なくなった)。何が起こっているのかを確認できるように、もう少しコードを投稿することをお勧めします..

于 2008-09-18T02:07:27.157 に答える
2

From the example you gave, this is not a scoping issue, or none of the parameters would work.

Looks like DBI (or a DBD, not sure where bind parameters are used) isn't honoring tie magic. The workaround would be to stringize or copy what you pass to it, like your second and third parameters do.

A simple test using SQLite and DBI 1.53 shows it working ok:

$ 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

Care to share what database you are using?

于 2008-09-18T09:35:59.543 に答える
2

まず、それは do のコンテキスト/スコープにはありません。それはまだメインまたはグローバルのコンテキストにあります。サブルーチンまたは perl のさまざまな「クラス」に関連する何らかの方法で {} を入力するまで、コンテキストを離れることはありません。() 括弧内では、スコープを離れていません。

あなたが私たちに提供したサンプルは、初期化されていないハッシュのものであり、Pi が示唆したように、strict を使用すると確実にそれらが発生しなくなります。

コードのより代表的な例を教えてください。%IN をどこでどのように設定していますか?

于 2008-09-18T01:54:44.283 に答える
2

DBI のどのバージョンを使用していますか? DBI 変更ログを見ると、1.00 より前のバージョンでは属性引数がサポートされていないようです。「初期化されていない」$in{test}は、実際にundefあなたが渡しているものだと思います$dbh->do()

于 2008-09-18T03:19:11.350 に答える
1

DBI ドキュメントによると、現在、関連付けられた変数のバインドは機能しません。

DBI は内部では非常に複雑であり、残念ながら、問題を引き起こしている効率性を高めるためにいくつかの回転を経ています。私は、醜い古い cgi-lib スタイルのコードを取り除こうと言う他のすべての人に同意します。優れたフレームワーク (go Catalyst) なしで CGI を実行するのは十分に不愉快です。

于 2008-11-24T18:31:57.780 に答える
0

http://www.carcomplaints.com/test/test.pl.txtからテストコードを試しましたが、コンピューターですぐに機能し、問題はありません。期待どおりに3つの値を取得します。私はそれをCGIとして実行しませんでしたが、以下を使用しました。

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

コンソール(test=test)に変数を記述すると、スクリプトが問題なく挿入されます。

ただし、これを省略した場合、ttは空の文字列と2つのNULLを挿入します。これは、値を文字列に補間するためです。これにより、現在の値を持つ文字列が作成さ$in{test}undefます。undefデータベースに挿入される空の文字列に文字列化します。

于 2008-09-25T08:23:52.300 に答える
0

これがtie()問題のように見え始めているので、次の実験を試してください。これを foo.pl として保存し、次のように実行します。perl foo.pl "x=1"

use CGI;

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

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

印刷する必要があります1 1。そうでない場合は、犯人が見つかりました。

于 2008-09-18T04:00:50.533 に答える
0

さて、これを試してください:

CGI を使用します。
私の %in;
CGI::ReadParse(\%in);

宣言した変数を実際に使用しているため、スコープを制御できるため、これが役立つ場合があります(さらにuse strict、水を濁らせる可能性のある他の不快感をなくすことができます)

于 2008-09-18T02:49:55.180 に答える
-1

これを試して

%in = ReadParse();

しかし、私はそれを疑います。クエリ パラメータなどを取得しようとしていますか?

于 2008-09-18T02:21:36.700 に答える