【问题标题】:Perl/DBI selectrow_array scope confusionPerl/DBI selectrow_array 范围混淆
【发布时间】:2020-05-21 15:01:25
【问题描述】:

所以,我有一个文件列表,我正在检查数据库表以查看是否存在条目并提取 id 和目标文件名。如果不存在,则插入一个条目并重新拉出该条目(注意 id 是自动递增的,所以无论我是否必须进行第二次查询。)

问题是当我在插入后重新拉出查询时,它进入的变量是词法的(我认为这是正确的措辞),一旦我离开 if (!defined) 块的范围,它就会失去它价值。

#lookup file db entry
my ($fileId, $destFilename) = $dbh->selectrow_array("select fileId, destFilename from myTable where sourceFilename = '$file'");
if (! defined $fileId) {
    # calculate out what the destination filename should be here..
    # add missing entry into table
    ($fileId, $destFilename) = $dbh->selectrow_array("select fileId, destFilename from myTable where sourceFilename = '$file'");
    print Dumper $destFilename;
}
print Dumper $destFilename;

这将导致:

$VAR1 = "correctfilenamehere"
$VAR1 = undef

我尝试在通过 selectrow_array 调用分配变量之前定义变量。对于这些变量,我已经尝试将上面的变量从 my 更改为 our。我对它为什么这样做感到困惑。

还要注意,这段代码在另一个块中,所以这些变量已经是那个范围的词法。我原以为它们会在子块中可用,但据我所知,它并没有真正以这种方式工作。

【问题讨论】:

  • 这不是作用域的工作方式;您编写的代码不会这样做。其他事情正在发生。
  • 请注意,您的$file 参数应作为参数绑定,而不是插入到字符串中,这是very dangerous$dbh->selectrow_array("select fileId, destFilename from myTable where sourceFilename = ?", undef, $file);
  • 至于绑定,如果它涉及文件系统中文件名以外的任何输入,我完全同意。但是,当仅使用文件系统中的文件名作为输入时,这在受限环境中应该是相当安全的。
  • 可以避免恶意活动,但文件名很容易破坏查询。在所有情况下,绑定参数都是最简单和最好的方法。

标签: perl dbi


【解决方案1】:

您发布的代码没有表现出您描述的行为。

$ perl -e'
   use strict;
   use warnings;

   use Data::Dumper qw( Dumper );

   sub f { $_[0] ? (4, "abc") : () }

   my ($fileId, $destFilename) = f(0);
   if (!defined $fileId) {
       ($fileId, $destFilename) = f(1);
       print Dumper $destFilename;
   }

   print Dumper $destFilename;
'
$VAR1 = 'abc';
$VAR1 = 'abc';

如果您引入一个具有相同名称的新变量,您可以获得所描述的行为。

$ perl -e'
   use strict;
   use warnings;

   use Data::Dumper qw( Dumper );

   sub f { $_[0] ? (4, "abc") : () }

   my ($fileId, $destFilename) = f(0);
   if (!defined $fileId) {
       my ($fileId, $destFilename) = f(1);
       print Dumper $destFilename;
   }

   print Dumper $destFilename;
'
$VAR1 = 'abc';
$VAR1 = undef;

【讨论】:

    【解决方案2】:

    发现了问题,一些代码正在创建一个同名的词法变量,而我没有注意到,因此父 $destFilename 被替换为本地变体。

    【讨论】:

    • 遗憾的是,当它发生在嵌套范围内时,无法自动检测到这种掩码,因为这是一种完全合理(尽管可能令人困惑)的编码实践。如果您在同一范围内屏蔽词汇,则会出现警告。
    • @Grinnz,关于“当它发生在嵌套范围内时,不可能自动检测到这种屏蔽”,我相信perlcritic 对此有一个规则。 (我希望use warnings; 就足够了。您希望多久在同一范围内使用两个具有相同名称的变量。)
    • @ikegami 我的意思是,无法判断它是否是有意的。确实很少见,但确实会发生
    • @Grinnz,我从未见过。如果我这样做了,我会说“你疯了吗?使用不同的名字!”也许如果一个是顶级的,一个是在一个子级的。这可能是由于重构而发生的。但是一个子中有两个同名的变量?那很臭,应该发出警告。
    猜你喜欢
    • 2020-02-16
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多