При настройке кода Perl для запуска в виде либо script или модуля, в чем причина __PACKAGE__?

В этом qaru.site/info/36205/... и особенно brian d foy "Как Script становится модуль" Я читал о том, как настроить код, чтобы он мог запускаться либо как Script, либо с помощью этого метода:

package SomeModule;

__PACKAGE__->run(@ARGV) unless caller();

sub run {
    # Do stuff here if you are running the file as
    # a script rather than a module.
}

Какова цель __PACKAGE__ в этой настройке? Почему бы просто не сделать это?

run(@ARGV) unless caller();

Ответ 1

Если вы скажете __PACKAGE__->run(@ARGV), то run может быть определен в классе, который вы наследуете или позволяете классу наследовать от этого. Если вы просто скажете run(@ARGV), вам не хватает информации о классе. Это имеет значение только в том случае, если вы программируете стиль OO.

Поместите следующее в файл с именем Foo.pm, а затем скажите perl Foo.pm 1 2 3

package Foo;

use strict;
use warnings;

__PACKAGE__->main(@ARGV) unless caller;

sub main {
    my $class = shift;
    my $obj   = $class->new(@ARGV);
    print $obj->to_string, "\n";
}

sub new {
    my $class = shift;
    return bless [@_], $class;
}

sub to_string {
    my $self = shift;
    return "args: " . join ", ", map { "[$_]" } @$self;
}

1;

Теперь поставьте следующее в Bar.pm и скажите perl Bar.pm a b c.

package Bar;

use strict;
use warnings;

use base 'Foo';

__PACKAGE__->main(@ARGV) unless caller;

sub to_string {
    my $self = shift;
    return "args: " . join ", ", map { "<$_>" } @$self;
}

1;

Теперь давайте посмотрим, что произойдет, если вы не используете __PACKAGE__ в этой среде. Сделать первый раздел кода в Foo.pm выглядеть следующим образом:

main(@ARGV) unless caller;

sub main {
    my $obj = Foo->new(@ARGV);
    print $obj->to_string, "\n";
}

Теперь запустите perl Foo.pm 1 2 3. Все должно выглядеть правильно. Теперь попробуйте запустить perl Bar.pm a b c. Мы по-прежнему получаем выход, но это не тот результат, который мы ожидаем. Что произойдет, если мы удалим __PACKAGE__ из Bar.pm? Ну, мы получаем и ошибку: Undefined subroutine &Bar::main called at Bar.pm line 8. Это потому, что нет main функции в модуле, и мы не вызываем его с классом, поэтому он больше не будет искать его в пакете Foo.