我有一个能够定义凭证的类。
$po = PoService->new()->set_basicauth("jack", "secret");
问题是,为了做到这一点,它必须重新定义模块子程序。所以,我这样做了:
sub set_basicauth {
my ($self, $creds_username, $creds_password) = @_;
sub SOAP::Transport::HTTP::Client::get_basic_credentials {
return $creds_username => $creds_password;
}
return $self;
}
但是,当我运行代码时,它会告诉我一条消息:
Variable "$creds_username" will not stay shared at /opt/PoService.pm line 53.
Variable "$creds_password" will not stay shared at /opt/PoService.pm line 53.
我在这里做错了什么?
答案 0 :(得分:1)
问题是词汇(my
)变量和嵌套子例程的混合。
内部子程序关闭它使用的两个变量。然而,作为词汇,它们在每次新调用时都被重新定义,而内部(名为)子元素忠实地保持对原始值的引用。因此,整个事情可能只在第一次调用时才能正常工作。
幸运的是,我们得到了警告。添加use diagnostics;
(或查看perldiag)
变量“$ x”不会在-e第1行(#1)保持共享 (W闭包)内部(嵌套)命名子例程引用a 在外部命名子例程中定义的词法变量。
当调用内部子程序时,它将看到的值 外部子例程的变量与第一个之前和期间的变量一样 调用外部子程序;在这种情况下,第一次调用之后 外子程序完成后,内子程序和外子程序都没有 更长时间共享变量的公共值。换句话说, 变量将不再被共享。
这个问题通常可以通过制作内部子程序来解决 匿名,使用sub {}语法。当内在的匿名潜艇那个 它们是外部子程序中的引用变量 会自动反弹到这些变量的当前值。
虽然这解释了问题,但如果我理解的话,解决方案将不适用于您的目的。
一种看似合适的方法是完全限定名称
sub SOAP::Transport::HTTP::Client::get_basic_credentials {
return $main::$creds_username => $main::$creds_password;
}
sub set_basicauth {
my $self = shift;
($main::$creds_username, $main::$creds_password) = @_;
# ... (not sure of your purpose, presumably use SOAP::)
return $self;
}
其中$main
应替换实际的包名称(如果不同)。 sub也可以放在另一个中,但是没有任何意图,因为它被编译为任何其他命名的sub。
另一种选择是使用our使变量成为全局变量。
答案 1 :(得分:1)
没有嵌套的命名潜艇。
sub set_basicauth {
my ($self, $username, $password) = @_;
$self->{username} = $username;
$self->{password} = $password;
}
sub request {
my ($self, ...) = @_;
my $username = $self->{username};
my $password = $self->{password};
local *SOAP::Transport::HTTP::Client::get_basic_credentials = sub {
return $username => $password;
};
... code that uses SOAP::Lite ...
}