2011-12-07 5 views
2

함수 login로부터 리턴 된 값이 전달 된 값과 일치하지 않는 이유를 이해할 수 없습니다. 펄에 PHP에서 일부 코드를 변환하여 펄을 배우려고 노력하는 동안 다음 Perl이 값을 함수로 전달하는 데 어려움이 있습니다.

내 코드

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 
    } 

의 조각입니다. 나는이 문제에 부딪쳤다. 나는 몇 가지 대안을 시도했지만 분명히 내가 얻지 못하는 것이있다!

답변

8

당신은 함수가

my $valid_user = $obj->login($thisuser, $thisuser_pass); 

처럼 첫 번째 매개 변수는 일반적으로 당신이 $ 누락 때문에 $ 자체

누락

sub login 
{ 
    my ($self , $user , $password) = @_; 
} 

으로 수행이입니다 호출 할 때 너 자신 사용자는 실제로 obje이다. ct이고 비밀번호은 실제로 사용자입니다.

C++, Java 또는 C#과 같은 다른 객체 지향 언어에서 온 경우이은 perl gotcha (말장난 없음)입니다.). 또 다른 하나는 심지어 객체 메소드에서 당신이 객체를 사용하면 늘

callAnotherObject($user); 

Also I see that you are using function prototypes, It may not work as you intend it to be.

+0

Perl의 프로토 타입에 대한 경고 용 +1 – tadmc

+1

프로토 타입은 메서드 호출에서 완전히 무시됩니다 (잘못된 프로토 타입을 눈치 채지 못한 이유입니다). – cjm

5

을 당신이

$self->callAnotherObject($user); 

단순히 호출처럼 자기를 사용할 필요가 또 다른 멤버 메소드를 호출 할 경우이다 방향 지정된 문법 ($obj->login($thisuser, $thisuser_pass))은 서브 루틴을 호출하기 위해 첫 번째 인수가 개체 자체가됩니다. 당신은 말을해야, 당신은 일반적으로 객체 지향 모듈과 같은 구문을 사용하여 표시됩니다

sub login { 
    my ($self, $user, $pass) = @_; 
    ... 
} 

덧붙여, 당신이 좋은 이유없이 프로토 타입 (($$)) 사용할 수 없습니다. Perl의 프로토 타입은 다른 언어와 같은 방식으로 사용되지 않으며, 어쨌든 프로토 타입은 간접 구문을 사용하여 서브 루틴을 호출 할 때 무시됩니다. (운좋게도 3 개의 인수로 호출하기 때문에 가능합니다.)

+0

나는 답을 보지 않는 프로토 타입 물건을 추가하고 추가했다. (나는 맹세한다.) –

+1

Nitpick, 그러나'$ obj-> foo'는 [간접 구문]이 아니다. (http://perldoc.perl.org/perlobj. html # Indirect-Object-Syntax), 그것은 단지 OO 메소드 구문입니다. 간접 메소드 구문은'foo $ obj'를 할 때 사용됩니다. 물론 이것은 피해야합니다. – friedo

+0

감사합니다 friedo - 그것에 대해 혼란스러워했습니다 – mob

1

Mythbusters를 보십니까?

당신이 아담과 제이미 할 정말, 정말 위험한 물건, 그들은 모든 프로그램의 시작 부분에 경고를 볼 수 있지만

"집에서이 작업을 수행하지 마십시오."같은 방식으로 Perl prototypes 생각하십시오. 사용하면 심하게 화상을 입을 가능성이 있습니다.


자, 이제 누가 당신의 login 함수를 호출한다? 아니면 더 좋을 수도 있습니다.

Perl 모듈을 사용하는 경우 로그인 서브 루틴을 다음과 같은 기본 프로그램에서 호출해야합니까?

my $package_obj = Another_package->new; 
$package_obj->login($user, $password); 

또는, 당신은 사용자의 편의를 위해 패키지에 사용이 일부 서브 루틴을 그리고 당신은 간단한 서브 루틴으로 사용하고,이 같은 아닌 개인 방법 :

package Another_package; 

sub new { 
    ... 
} 

sub foo { 
    ... 
    my $user = login ($user, $password); 
} 

당신이 경우 두 번째 예에서와 같이 패키지 내부에 간단한 서브 루틴 같은 login 서브 루틴을 호출 아무런 문제 될 것이 없다.

그러나 전체 자란처럼 로그인 서브 루틴을 치료하는 경우 방법 (나는 첫 번째 예에서와 같이), 당신이 방법은 서브 루틴의 첫 번째 매개 변수로 자신의 클래스 개체를 전달할 수 있음을 기억해야합니다.

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 클래스의 구조를 변경하면 변경 사항이 코드의 특정 부분에서 분리됩니다. 디버깅이 훨씬 쉬워집니다.

될 것 로그인 서브 루틴을 작성하는 더 좋은 방법 :이 예에서

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

, 내 사용자 이름과 암호를 설정하는 세터/getter 메소드를 사용하고 있습니다. 이 방법으로, 나는 그들이 실제로 내 물건에 어떻게 저장되는지 걱정할 필요가 없다.

setter/getter 메소드를 사용하는 Another_Package 모듈은 다음과 같습니다. 원하는 경우 사용자가 생성자를 호출 할 때 사용자와 암호를 전달할 수있게되었습니다. 내 새로운 생성자 서브 루틴

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

공지 사항 나는 $self 익명 해시 (my $self = {})를 만들고 나는 즉시 그것을 축복. 자, $self은 이미 패키지 객체이며, 많은 객체를 setter/getter 메소드로 호출하여 여러 필드를 설정할 수 있습니다. 내 새로운 생성자는 내 실제 Another_module 객체가 어떤 모습인지 전혀 알 수 없습니다.

로그인 메서드 서브 루틴에서는 사용자 및 암호를 설정하는 데에도 동일한 setter/getter 메서드를 사용합니다. 다시, 내 로그인 메서드는 이러한 필드이 개체에 저장되는 방법에 대해 아무것도 모릅니다.

내 눈에 보일 수도있는 또 하나의 점은 내 모듈에 $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 :-("; 
    } 
} 

그래서, 내 세터/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}; 
} 

가 왜 $self->{USER_INFO}->{USER}에서 $user하지 $self->{USER}를 저장합니까? 전혀 이유가 없습니다. 그러나 나머지 모듈이 사용자 및 암호를 저장하는 위치와 방법에 상관하지 않음을 보여줍니다.

+0

제 질문에 대한 답변을 얻었습니다. 문제를 해결합니다. 나는 여전히 코드를 만들고 있는데, 로그인 함수는 지금까지 사용자 이름과 패스워드를 검사하는 데이타베이스를 가지고 있으며 올바른 경우 일부 세션 변수를 생성하고 1이나 0을 리턴한다. 이것은 첫 번째처럼 메인 프로그램에서 호출된다. 예. –

관련 문제