我遇到了以前从未遇到过的变量范围问题。我正在使用 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 占位符变量的计算结果就像未初始化一样。另外两个占位符变量起作用。

问题:为什么 %in 哈希在 do() 上下文中不可用,除非我将其用双引号(#2 占位符)括起来或将值重新分配给新变量(#3 占位符)?

我认为这与 CGI 模块的 ReadParse() 函数如何将范围分配给 %in 散列有关,但我不太了解 Perl 范围,无法理解为什么 %in 在顶层可用,但在我的 do 中不可用() 陈述。

如果有人确实理解范围界定问题,是否有更好的方法来处理它?将所有 %in 引用括在双引号中似乎有点混乱。为每个查询参数创建新变量是不现实的。

需要明确的是,我的问题是关于变量范围问题。我意识到 ReadParse() 不是使用 CGI 获取查询参数的推荐方法。

我正在使用 Perl 5.8.8、CGI 3.20 和 DBI 1.52。预先感谢阅读本文的任何人。

@Pi 和@Bob,感谢您的建议。预先声明 %in 的范围没有效果(我总是使用 strict)。结果与之前相同:在数据库中,col1 为空,而 cols 2 和 3 设置为预期值。

作为参考,这里是 ReadParse 函数(见下文)。它是一个标准函数,是 CGI.pm 的一部分。按照我的理解,我并不是为了设置范围而初始化 %in 哈希(除了满足严格要求),因为在我看来该函数可以处理该问题:

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

我想我的问题是在 do() 上下文中获取 %in 哈希的最佳方法是什么?再次感谢!我希望这是为我原来的问题提供更多信息的正确方式。

@担:我听到你提到 &ReadParse 语法。我通常会使用 CGI::ReadParse() 但在这种情况下我认为最好坚持如何使用 CGI.pm 文档中有它 确切地。

有帮助吗?

解决方案

根据 DBI 文档:目前,绑定绑定变量不起作用。

DBI 在幕后相当复杂,不幸的是,为了提高效率,要经历一些旋转,从而导致您的问题。我同意其他人所说的要摆脱丑陋的旧 cgi-lib 风格代码的观点。在没有一个好的框架(使用 Catalyst)的情况下进行 CGI 已经够令人不快的了,更不用说那些已经过时了十年的东西了。

其他提示

它实际上看起来并不像您按照文档中所述使用它:https://metacpan.org/pod/CGI#COMPATIBILITY-WITH-CGI-LIB.PL

如果必须使用它,那么 CGI::ReadParse();看起来更明智,语法也更简洁。虽然我看不出它在这种情况下有多大区别,但它是一个绑定变量,所以谁到底知道它在做什么;)

是否有特殊原因不能使用更常见的 $cgi->param('foo') 语法?它更干净一点,并且以一种更可预测的方式弄脏您的名称空间。

use strict;. 。总是。

尝试声明

our %in;

看看是否有帮助。如果失败的话, strict 可能会产生更有用的错误。

我不知道出了什么问题,但我可以告诉你一些事情:

  • 这不是范围界定问题。如果是的话,则没有任何实例 $in{test} 会工作。
  • 这不是古风 & 调用语法。(这不是“正确的”,但在这种情况下是无害的。)

ReadParse 是一段令人讨厌的代码。它修改符号表以在调用包中创建全局变量 %in 。更糟糕的是它是一个绑定变量,因此访问它可以(理论上)做任何事情。查看 CGI.pm 的源代码, FETCH 方法只是调用 params() 方法来获取数据。我不知道为什么要在 $dbh->do() 不工作。

首先,这不在 do 的上下文/范围内。仍然是在main或者global的背景下。在以某种与 Perl 中的子例程或不同“类”相关的方式输入 {} 之前,您不会离开上下文。在 () 括号内,您不会离开范围。

您给我们的示例是未初始化的哈希,正如 Pi 所建议的,使用 strict 肯定会阻止这些情况发生。

您能给我们一个更具代表性的代码示例吗?您在哪里设置 %IN 以及如何设置?

那里有些东西坏了。Perl 的作用域相对简单,除非您正在做一些愚蠢的事情,否则您不太可能偶然发现任何类似的奇怪事情。正如所建议的,打开严格的编译指示(以及警告。事实上无论如何你都应该使用两者)。

如果不知道 %in 是如何定义的,就很难判断发生了什么(这与那个令人讨厌的 ReadParse 调用有关吗?你为什么用前导 & 来称呼它,顺便说一句?该语法已被认为已经死亡并消失了很长一段时间)。我建议发布更多代码,以便我们可以看到发生了什么。

您使用什么版本的 DBI?从看 DBI 变更日志 1.00 之前的版本似乎不支持 attribute 参数。我怀疑“未初始化” $in{test} 实际上是 undef 你要传递到的 $dbh->do().

从你给出的例子来看,这是 不是 范围问题,或者所有参数都不起作用。

看起来 DBI(或 DBD,不确定在哪里使用绑定参数)不尊重领带魔法。解决方法是字符串化或复制传递给它的内容,就像第二个和第三个参数一样。

使用 SQLite 和 DBI 1.53 进行的简单测试表明它工作正常:

$ 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

愿意分享您正在使用的数据库吗?

好的,试试这个:

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

这可能会有所帮助,因为它实际上使用了您已声明的变量,因此可以控制其范围(加上它会让您 use strict 没有其他可能使水变得浑浊的肮脏行为)

因为这开始看起来像 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. 。如果没有,我们就找到了罪魁祸首。

我刚刚尝试了你的测试代码 http://www.carcomplaints.com/test/test.pl.txt, ,并且它可以立即在我的计算机上运行,​​没有任何问题。我得到了预期的三个值。我没有将其作为 CGI 运行,而是使用:

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

我在控制台上写了一个变量(test=test)并且您的脚本插入没有问题。

然而,如果您忽略这一点,tt 将插入一个空字符串和两个 NULL。这是因为您将一个值插入到字符串中。这将生成一个值为 $in{test} 这是 undef 眼下。 undef string化为空字符串,该字符串将被插入到数据库中。

尝试这个

%in = ReadParse();

但我对此表示怀疑。您是否正在尝试获取查询参数或其他内容?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top