在Perl中,如果在函数之间传递(通过return或input param),则从DBI-> connect返回的对象/句柄超出范围?

时间:2011-09-14 16:15:48

标签: perl function scope dbi prepare

我收到此错误

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

代码类似于以下(代码段):

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

othermodule1:

my $databaseHandler = unset;

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

othermodule2:

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

2 个答案:

答案 0 :(得分:6)

  $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)不显示/重要,因为第一个模块的{{1}声明将该变量放在文件其余部分的范围内(包括主脚本)。但如果你的模块在自己的文件中,它将停止工作(下面的第二个例子)

my $databaseHandler

答案 1 :(得分:2)

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

所以在该模块之外看不到othermodule1中的my $databaseHandler。该值可以从函数返回,但该变量名称对模块是私有的。