Что означает эта строка кода Perl?

У меня есть файл perl mason, и одна из строк выглядит так:

$result = PI::Membership::Service->cancel(name => $name)

Что именно это значит? Он вызывает другой модуль? Это объектно-ориентированный Perl-код?

Спасибо


person Joey Franklin    schedule 08.07.2013    source источник


Ответы (2)


Он вызывает (вызывает) подпрограмму PI::Membership::Service::cancel с тремя аргументами.

  1. "PI::Membership::Service"
  2. "name"
  3. $name

Учитывая обычные соглашения об именах, это вызывает подпрограмму с именем cancel в пакете PI::Membership::Service, определенную в файле с именем PI/Membership/Service.pm где-то по пути @INC (однако существует много ненормальных соглашений об именах, поэтому нет гарантии, что вы найдете такой файл) . И если пакет (класс) PI::Membership::Service наследуется от одного или нескольких других пакетов, подпрограмма cancel фактически может быть определена в одном из этих пакетов.

Подробнее см. perlobj.

person mob    schedule 08.07.2013
comment
Итак, учитывая обычные соглашения об именах, какой файл будет вызываться? - person Joey Franklin; 08.07.2013
comment
@JoeyFranklin — PI/Membership/Service.pm, как сказано в ответе. - person Quentin; 08.07.2013
comment
Хотя определение элементов в пространстве имен PI::Membership::Service с файлом в одном из каталогов вашей библиотеки с именем вроде PI/Membership/Service.pm не является чем-то необычным, нет никаких гарантий. Вам следует обратиться к исходному коду для операторов use или require. - person tjd; 08.07.2013
comment
Этот ответ предполагает, что PI::Membership::Service не наследует метод cancel. Он может быть определен в родительском классе. - person friedo; 08.07.2013

Если $result не является объектом Pi::Membership::Service, это не совсем объектно-ориентированный вызов, потому что он не создает объект и не манипулирует им. Объектно-ориентированный вызов будет выглядеть так:

my $obj = Foo::Bar->new;   #Creating an object of class `Foo::Bar`
$obj->Baz                  #Calling method "Baz" on object "$obj";

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

Чтобы понять, что происходит на самом деле, вы должны знать о пространствах имен. Perl использует пространства имен. В большинстве случаев вы можете не знать об этом, потому что используете пространство имен по умолчанию main. Пространства имен необходимы, потому что вы можете столкнуться (особенно в версиях Perl до 4.x) с конфликтами имен функций и переменных. Вот программа, которую я написал в старом стиле Perl 3.x:

require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

А вот моя программа fribulate.pl:

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 6;
}
1;

Когда я запускаю свою программу, я получаю:

 Fribulated Value = 54. Original Value = 9

Ждать? Разве изначально не 4,5? Программа fribulate.pl повлияла на мой $value, потому что она также использует переменную с именем $value. Чтобы обойти это, Perl создал команду package, которая создает новое пространство имен:

package Fribulate;
sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

Теперь программа fribulate.pl находится не в пространстве имен main, а в пространстве имен Fribulate. Таким образом, переменная $value, используемая в fribulate.pl, отличается от моей переменной $value.

Однако я могу получить доступ к переменной в другом пространстве имен, если я добавлю к ней пространство имен:

require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

# Printing the value of $value from frimbulate.pl:
print "And in fribulate.pl, it's using $Fribulate::value\n";

Вы бы увидели это, если бы использовали Файл:Найти. Чтобы получить доступ к полному имени файла, вы используете $File::Find::name. Чтобы получить доступ к каталогу файла, вы используете $File::Find::dir. Пространство имен File::Find добавляется к переменным $dir и $name в File::Find.

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

require "fribulate.pl";
$value = 4.5;
$new_value = Frimbulate::fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

Чтобы обойти эту проблему, вы проделали небольшую причудливую работу в программе frimbulate.pl:

Package Frimbulate;

require Exporter;
@EXPORT = qw(frimbulate);

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

Пакет Exporter посыпает волшебной пылью1 функции в @EXPORT и делает их доступными в пространстве имен main — пространстве имен по умолчанию, в котором находятся все ваши вещи. Таким образом, такие модули, как File::Copy и File::Basename используйте Exporter, чтобы разрешить вам доступ к соответствующим подпрограммам copy и basename без добавления имени пакета перед ними.

Теперь это считается плохим стилем, потому что вы можете без предупреждения перезаписать другие подпрограммы с тем же именем. В новом стиле написания модулей вы больше не экспортируете автоматически все свои функции в массив @EXPORT. Вы заметите это в File::Path, который не экспортирует свои функции автоматически в пространство имен main без нашего явного запроса. Вместо этого вы помещаете их в @EXPORT_OK, что требует, чтобы пользователи просили их добавить в пространство имен:

Пакет Фримбулейт

Package Frimbulate;

require Exporter;
@EXPORT_OK = qw(frimbulate); #You have to request the frimbulate subroutine

sub fribulate {
    my $param = shift;
    $value = $param * 2;
    return $value * 3.1416;
}
1;

Моя программа:

# Now I have to ask that the frimbulate subroutine be import into my main namespace
require "fribulate.pl" qw(frimbulate);
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value  Original value = $value\n";

Теперь у вас должно быть достаточно информации, чтобы прочитать документацию по модулю Perl и, вполне возможно, понять, что происходит. Документация Perlmod охватывает пространства имен, таблицу символов и даже немного об области видимости переменных. Он содержит много информации и может быть немного пугающим без базовой информации.


1 При использовании модуля Exporter ни одна пикси не пострадала. Если вы посмотрите на Exporter.pm, который вы можете найти с помощью команды perldoc -l Exporter, вы увидите, что он напрямую манипулирует таблицей символов.

person David W.    schedule 08.07.2013