В 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 нельзя увидеть за пределами этого модуля. Значение может быть возвращено из функции, но это имя переменной является частным для модуля.