Perl трудности с передачей значений в функцию - PullRequest
2 голосов
/ 07 декабря 2011

Не могу понять, почему возвращаемые значения из функции login ниже не соответствуют тому, что ей передано.

Ниже приведен фрагмент моего кода

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
    }

При попытке выучить perl путем преобразования некоторого кода из php в perl.Я столкнулся с этой проблемой, я попробовал несколько альтернатив, но, очевидно, что-то я не получаю!

Ответы [ 3 ]

8 голосов
/ 07 декабря 2011

Когда вы вызываете такую ​​функцию, как

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

Первый параметр - , этот обычно делается как

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

Вы пропали без вести $ self

Поскольку вам не хватает $ self, вы пользователь на самом деле объект, а ваш пароль на самом деле пользователь .

Если вы используете другой объект, ориентированный на возражения, например C ++, Java или C #, этот - это perl gotcha (без каламбура :)). Еще одно, что даже из метода объекта, если вы хотите вызвать другой метод-член, вы должны использовать self, например

$self->callAnotherObject( $user );

Просто звонить не будет

 callAnotherObject( $user );

Также я вижу, что вы используете прототипы функций. Это может не сработать так, как вы предполагаете.

5 голосов
/ 07 декабря 2011

Когда вы используете объектно-ориентированный синтаксис ($obj->login($thisuser, $thisuser_pass)) для вызова подпрограммы, первым аргументом будет сам объект. Вы должны сказать, и вы обычно увидите, что объектно-ориентированные модули используют синтаксис, такой как:

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

Кстати, вы не должны использовать прототипы (($$)) без уважительной причины. Прототипы в Perl не используются так же, как в других языках, и в любом случае прототип игнорируется, когда вы вызываете подпрограмму с косвенным синтаксисом (к счастью, в вашем случае, поскольку вы фактически вызываете ее с 3 аргументами).

1 голос
/ 08 декабря 2011

Ты даже смотришь "Разрушители мифов"?

Хотя вы видите, что Адам и Джейми делают действительно очень опасные вещи, они предупреждают вас в начале каждой программы: " Не делайте этого дома. " Подумайте о Прототипах Perl таким же образом. Если вы используете их, есть большая вероятность, что вы сильно обожгетесь.


Хорошо, теперь, кто вызывает вашу 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 подпрограмму как полноценный метод (как я это делал в первом примере), вы должны помнить, что методы передают свой объект класса как первый параметр подпрограммы.

Таким образом, вам нужно сделать что-то вроде этого:

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

В этом примере я использую методы установки / получения для установки моего имени пользователя и пароля. Таким образом, мне не нужно беспокоиться о том, как они хранятся в моем объекте.

Вот ваш 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;
        }
    }

Обратите внимание, в моей новой подпрограмме конструктор я создаю $self анонимный хеш (my $self = {}) и сразу же благословляю его. Теперь $self уже является объектом пакета, и я могу вызвать несколько методов setter / getter для установки различных полей в моем объекте. Мой новый конструктор не знает, как выглядит мой фактический Another_module объект.

В моей подпрограмме Login , я также использую те же методы установки / получения, чтобы установить пользователя и пароль. Опять же, мой Login метод ничего не знает о том, как эти поля хранятся в объекте.

Еще одна вещь, которую вы можете заметить, это то, что я устанавливаю скаляр с именем $login_successful в моем модуле Login , чтобы увидеть, был ли мой вход успешным. В 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 :-(";
     }
 }

Итак, как выглядят мои методы установки / получения? Они на самом деле довольно простые:

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 не волнует, где и как я храню пользователя и пароль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...