В Perl объект / дескриптор, возвращенный из DBI->connect, выходит из области видимости, если передается между функциями (с помощью параметра return или input)?

Я получаю эту ошибку

Невозможно вызвать метод "prepare" без ссылки на пакет или объект в... [в строке createSqlTable, начиная с моего $execute].

с кодом, подобным следующему (фрагменты):

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 ответа

Решение
  $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 объявление помещает эту переменную в область остальной части файла (включая основной скрипт). Но он перестанет работать, если ваш модуль находится в своем собственном файле (второй пример ниже)

$ 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

Вы смешиваете лексическую сферу и глобальную сферу. my объявляет переменную как лексическую - ее нельзя увидеть за пределами определяющей области. Без этого это (пакет) глобально, но вы получите предупреждение об этом, если вы use strict,

так my $databaseHandler внутри othermodule1 нельзя увидеть за пределами этого модуля. Значение может быть возвращено из функции, но это имя переменной является частным для модуля.

Другие вопросы по тегам