Perl 从类子例程重写模块子例程

Perl 从类子例程重写模块子例程,perl,Perl,我有一个类,它能够定义凭据 $po=posservice->new()->set_basicauth(“杰克”、“秘密”); 问题是,为了做到这一点,它必须重新定义一个模块子例程。所以,我是这样做的: subset\u basicauth{ 我的($self、$creds\u用户名、$creds\u密码)=@; 子SOAP::传输::HTTP::客户端::获取基本凭据{ 返回$creds\u username=>$creds\u password; } 返回$self; } 但是,当我运行代

我有一个类,它能够定义凭据

$po=posservice->new()->set_basicauth(“杰克”、“秘密”);
问题是,为了做到这一点,它必须重新定义一个模块子例程。所以,我是这样做的:

subset\u basicauth{
我的($self、$creds\u用户名、$creds\u密码)=@;
子SOAP::传输::HTTP::客户端::获取基本凭据{
返回$creds\u username=>$creds\u password;
}
返回$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.

我做错了什么?

问题是词法(
my
)变量和嵌套子例程的混合

内部子例程关闭它使用的两个变量。然而,由于词法上的原因,它们在每次新调用时都会被重新定义,而内部(命名)子对象忠实地保持对原始值的引用。因此,只有在第一次调用时,整个过程才可能像预期的那样工作

幸运的是,我们得到了这一事实的警告。使用
进行诊断已添加(或请参阅)

变量“$x”将不会在-e第1行(#1)上共享
(W闭包)内部(嵌套)命名子例程正在引用 在外部命名子例程中定义的词法变量

当调用内部子例程时,它将看到 外部子例程的变量在第一次 调用外部子例程;在这种情况下,在第一次调用 外部子例程完成后,内部子例程和外部子例程将不再显示 更长时间共享变量的公共值。换句话说 变量将不再被共享

这个问题通常可以通过制作内部子程序来解决 匿名,使用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中,但没有任何用途,因为它是作为任何其他命名sub编译的


另一种选择是使用全局变量。

没有嵌套命名子类

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

谢谢@zdim。我已将解决方案修改为有效解决方案。@sancho21 Great:)。谢谢你的建议编辑。然而,声明
my
vars是另一回事。它引入了一个词汇表,在这种情况下,它实际上是全局的(无论如何,在更大的范围内)。如果您随后引用它(
$var
),那么它就是词法,而不是
$main::var
——您总是要调用
$main::var
$main::var
在符号表中创建一个条目(而
my$var
不创建)。当完全合格时,它们不需要被声明(如果它不起作用,肯定还有其他原因)。我将添加一些评论或链接(但稍后,现在在这里已经太晚了)。