Ты даже смотришь "Разрушители мифов"?
Хотя вы видите, что Адам и Джейми делают действительно очень опасные вещи, они предупреждают вас в начале каждой программы: " Не делайте этого дома. " Подумайте о Прототипах 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
не волнует, где и как я храню пользователя и пароль.