【问题标题】:In Perl does the object/handle returned from DBI->connect go out of scope if passed between functions (by return or input param)?在 Perl 中,如果在函数之间传递(通过返回或输入参数),从 DBI->connect 返回的对象/句柄是否超出范围?
【发布时间】:2011-11-17 04:29:39
【问题描述】:

我收到此错误

如果没有包或对象引用,则无法在 ... [在 createSqlTable 行中以我的 $execute 开头] 调用方法“prepare”。

代码类似于以下(sn-ps):

use othermodule1;
use othermodule2;

my $dbh = othermodule1::connectToDatabase();

if ( defined $databaseHandler )
{
  print "\ndatabaseHandler is defined here after calling connectToDatabase\n";
}

othermodule2::setDatabaseHandler( $databaseHandler );

othermodule2::createSqlTable();

其他模块1:

my $databaseHandler = unset;

sub connectToDatabase
{
  $databaseHandler = DBI->connect('DBI:mysql:db','db','pwd') or die "Could not    connect to database: ";
}

其他模块2:

my $dbhandler = unset;

sub setDatabaseHandler
{
  $dbhandler = @_;
}


sub createSqlTable()
{
  my $query = "CREATE TABLE atable ( a CHAR(30) NULL, b CHAR(30) NULL )"; # etc...

  my $execute = $dbhandler ->prepare($myquery) or die "Couldn't prepare statement: " . $dbhandler->errstr;
  $execute->execute or die "Couldn't execute statement: " . $dbhandler->errstr;
}

【问题讨论】:

  • 顺便说一句,它是一个数据库handle(即一种识别数据库连接的方式),而不是一个handler(处理某事的东西)。

标签: perl function scope dbi prepare


【解决方案1】:

您正在混合词法范围和全局范围。 my 将变量声明为词法 - 在其定义范围之外无法看到它。没有它,它是(包)全局的,但如果你use strict,你会收到一个警告。

所以在其他模块1 内的my $databaseHandler 在该模块外看不到。该值可以从函数返回,但该变量名是模块私有的。

【讨论】:

  • 这可能是问题之一。 use strictuse warnings.
  • @mob - 我不太清楚这些模块是否定义在与main 包相同的文件中。如果它们是相同的(我的原始阅读),那不是问题。如果他们不是,它是,虽然恕我直言是由于意外使用了错误的变量名(请参阅我更新的答案)而不是故意错误的范围
  • @mob 我使用严格使用警告
  • 您指出的问题是我的错字。我应该在 connectToDatabase 中返回句柄。我还问过返回句柄或对它的引用是否有效,使用 return \$databaseHandler (进入 $dbh - 我真的应该调用 $dbhref )然后使用 ${ $dbh deref } 来处理。只是想知道如果句柄是我正在传递的对象,我是否引入了低效率。
  • +1 @DVK 这不是根本问题——你解决了这个问题。谢谢你。但他是对的,这是(另一个)问题,正如我在之前的评论中所说,我应该从 connectToDatabase 返回一个值 - 实际上这是一个错字,我的原始代码没有这个错误。
【解决方案2】:
  $dbhandler = @_;

是问题所在。您在标量上下文中分配 - 因此 scalar(@_) 的值将分配给 $dbhandler - 在本例中为 1,因为您传递了 1 元素参数列表。

它应该是:($dbhandler) = @_; 使用列表上下文或作为替代成语,$dbhandler = shift;

对比度:

$ perl -e 'sub x { $x = @_ ; print "$x\n"} ; x(33);'
1
$ perl -e 'sub x { ($x) = @_ ; print "$x\n"} ; x(33);'
33

第二个不相关的问题是您错误地命名了变量。您在主脚本中有$dbh,但在分配它之后您继续使用$databaseHandler

if ( defined $databaseHandler )  # BAD
if ( defined $dbh )              # GOOD

上述错误(使用$databaseHandler而不是$dbh)不会出现/如果您的模块与上面的主脚本定义在同一个文件中,因为第一个模块的my $databaseHandler声明将该变量放在文件其余部分的范围(包括主脚本)。但它会STOP工作,如果您的模块在自己的文件中(下面的第二个示例)

$ cat /tmp/p1.pm
package p1;
my $v = undef;
sub x {
    $v = 3;
}
1;
$ cat /tmp/x1.pl
use p1;
my $c = p1::x();
my $v_print =  defined $v ? $v : "_UNDEF_";
print "v=$v_print\nc=$c\n";

$ perl -I /tmp /tmp/x1.pl
v=_UNDEF_
c=3

###############################################

$ cat /tmp/x2.pl
package p1;
my $v = undef;
sub x {
    $v = 3;
}
1; # END package p1
package main;
my $c = p1::x();
my $v_print =  defined $v ? $v : "_UNDEF_";
print "v=$v_print\nc=$c\n";

$ perl /tmp/x2.pl
v=3
c=3

【讨论】:

  • +1 并接受答案:($dbhandler) = @_;那是我的问题的根本原因。另一个问题是:传递处理程序是否有效(即它是一个对象)还是将其作为参考返回更好,即新代码将是 sub connectToDatabase { $databaseHandler = DBI->connect('DBI: mysql:db','db','pwd') or die "Could not connect to database:";返回 /$databaseHandler; } 然后做: $dbref = connectToDatabase() 并通过 ${ dbref } 的想法去引用它?
  • 附言。那应该是 ${ $dbref } 而不是 ${ dbref }
  • @Rob - 就像在 Java 中一样(但出于不同的原因),从来没有“对象”被传递。被传递的值已经是对对象的引用,通过设计语言中对象的实现方式(在 Perl 的情况下,通过底层的祝福引用,通常是散列)。所以,TL;DR 版本是“没有理由做\$databaseHandler;”。
  • @ROB - ...好吧,为了简单起见,我在最后一条评论中撒了一点小谎 - IIRC 你也可以祝福一个普通的标量而不是一个引用(参见由内而外的对象),但这不会改变您问题的答案。传递的“对象”值始终是一个有福的标量,无论是否引用,并且不需要进一步引用它。
  • +1 x2 @DVK 很高兴知道不需要进一步的参考。在这种情况下,我将不得不在我今天刚刚编写的代码中撤消这一切。但这一切都奏效了!但这没关系。它会让它更易于维护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 1970-01-01
  • 2013-11-29
  • 2017-06-24
相关资源
最近更新 更多