无法理解为什么函数login down的返回值与传递给它的内容不对应。
以下是我的代码片段
package This_package;
.......
# returned from function that parses post data ($reqparam)
my $thisuser = $$reqparam{"username"};
# escape '@', username is an email
$thisuser =~ s/@/\@/;
my $thisuser_pass = $$reqparam{'password'};
print $thisuser; # ok
print $thisuser_pass; # ok
my $obj = new users;
my $valid_user = $obj->login($thisuser, $thisuser_pass);
.......
package Another_package;
sub new {
my ($class) = @_;
my $self = {
_login => undef,
_create_user => undef,
....
};
bless $self, $class;
return $self;
}
sub login ($$){
my ($user, $pass) = @_;
# some processing
.....
return $user; # prints users=HASH(...)
# return $pass; # prints the value of $user (the actual value)
# instead of the value of $pass
}
尝试通过将一些代码从php转换为perl来学习perl。 我遇到了这个问题,我尝试了一些替代方案,但显然有一些我没有得到的东西!
答案 0 :(得分:8)
当您调用类似
的功能时 my $valid_user = $obj->login($thisuser, $thisuser_pass);
第一个参数此通常以
完成sub login
{
my ( $self , $user , $password ) = @_;
}
您缺少 $ self
由于您缺少$ self,您用户实际上是对象,您的密码实际上是用户。
如果您来自另一种受到反对的语言,例如 C ++,Java或C#,那么就是一个perl陷阱(没有双关语:))。另一个是,即使从一个对象方法,如果你想调用另一个成员方法,你必须使用像
这样的自我$self->callAnotherObject( $user );
简单地打电话不要做
callAnotherObject( $user );
Also I see that you are using function prototypes, It may not work as you intend it to be.
答案 1 :(得分:5)
当您使用面向对象的语法($obj->login($thisuser, $thisuser_pass)
)来调用子例程时,第一个参数将是对象本身。您应该说,您通常会看到面向对象的模块使用如下语法:
sub login {
my ($self, $user, $pass) = @_;
...
}
顺便说一下,如果没有充分的理由,你不应该使用原型(($$)
)。 Perl中的原型的使用方式与其他语言中的原型不同,在任何情况下,当您使用间接语法调用子例程时,都会忽略原型(幸运的是,在您的情况下,因为您实际上是使用3个参数调用它)。
答案 2 :(得分:1)
你甚至看过流言终结者?
虽然你看到亚当和杰米做了非常非常危险的事情,但他们在每个节目的开头都警告你,“不要在家里这样做。”想想Perl prototypes以同样的方式。如果你使用它们,你很可能会被严重烧伤。
好的,现在谁在调用你的login
功能?或者,也许更好,它是如何被称为的?
如果我使用你的Perl模块,我是否可以从我的主程序中调用 login 子程序?
my $package_obj = Another_package->new;
$package_obj->login($user, $password);
或者,这是为了方便你在包中使用的一些子程序,你将它用作一个简单的子程序,而不是像这样的私有方法:
package Another_package;
sub new {
...
}
sub foo {
...
my $user = login ($user, $password);
}
如果你将login
子程序作为一个简单的子程序 打包 ,就像在第二个例子中那样,一切都应该没问题。
但是,如果您将 login 子例程视为完整的承诺方法(就像我在第一个示例中所做的那样),您必须记住方法通过他们的类object作为子例程的第一个参数。
因此,你需要做这样的事情:
sub login {
my $self = shift; #Pointer to the Another_package object I'm using
my $user = shift;
my $password = shift; #I just love lining things up!
$self->{USER} = $user; #Bad way of doing it.
$self->{PASSWD} = $password;
... #Some processing.
return $user;
}
为什么#Bad way of doing it
发表评论?因为你真的想让你的内部尽可能分开。这样,如果您对Another_package
类的结构进行了更改,则您的更改将在代码的特定部分中被隔离。它使调试更容易。
编写 login 子例程的更好方法是:
sub Login { #In standard Perl, methods are capitalized.
my $self = shift; #Pointer to Another_package object
my $user = shift; #Allow user to pass user and password in constructor
my $password = shift; #I just love lining things up!
$self->User($user); #Way better: This is a setter/getter method
$self->Password($password);
... #Some processing.
return $user;
}
在这个例子中,我使用setter / getter方法来设置我的用户名和密码。这样,我不必担心它们实际上是如何存储在我的对象中的。
这是使用setter / getter方法的Another_Package
模块。我现在允许用户在他们调用 new 构造函数时传入用户和密码。
package Another_package;
sub new {
my $class = shift;
my $user = shift;
my $password = shift;
my $self = {};
bless $self, $class;
$self->User($user);
$self->Password($password);
...
return $self;
}
sub Login {
my $self = shift;
my $user = shift;
my $pass = shift;
$self->Password($pass);
if (not defined $self->User($user)) {
croak qq(Cannot log in without a user ID);
}
...
if ($login_successful) {
return $self->User; #Or maybe a session instant
else {
return;
}
}
请注意,在我的 new 构造函数子例程中,我创建了一个$self
匿名哈希(my $self = {}
),我马上祝福它。现在,$self
已经是一个包对象,我可以调用一堆setter / getter方法来设置对象中的各个字段。我的 new 构造函数不知道我的实际 Another_module 对象是什么样的。
在我的 Login 方法子例程中,我也使用相同的setter / getter方法来设置用户和密码。同样,我的 Login 方法对这些字段如何存储在对象中一无所知。
您可能会注意到的另一件事是我在登录模块中设置了一个名为$login_successful
的标量,以查看我的登录是否成功。在Perl中,如果方法失败,则通常不返回任何内容,或者在成功时返回一些内容。这样,用户的程序可以测试以查看调用是成功还是失败。例如,如果登录失败,用户可能希望在放弃之前尝试一些默认密码:
my $package_obj = Another_package->new($user, $password);
my $foo = $package_obj->Login;
if (not defined $foo) {
foreach my $password qw(swordfish s3x mon3y 7ucky) {
$package_obj->Password($password);
last if $foo = $package_obj->Login;
}
if (not defined $foo) {
die "I don't know the password :-(";
}
}
那么,我的setter / getter方法是什么样的?它们实际上非常简单:
sub User {
my $self = shift;
my $user = shift;
if(defined $user) {
$self->{USER_INFO}->{USER} = $user;
}
return $self->{USER_INFO}->{USER};
}
sub Password {
my $self = shift;
my $pass = shift;
if (defined $password) {
$self->{USER_INFO}->{PASSWORD} = $pass;
}
return $self->{USER_INFO}->{PASSWORD};
}
为什么我将$user
存储在$self->{USER_INFO}->{USER}
而不是$self->{USER}
?完全没有理由。但是,它确实显示Another_package
模块的其余部分并不关心我在何处或如何存储用户和密码。