Я просто ненавижу как CGI:: средство доступа Приложения для CGI
объект называют query
.
Я хотел бы, чтобы мои классы экземпляра были в состоянии использовать названное средство доступа cgi
добираться CGI
объект, связанный с текущим экземпляром моего CGI::Application
подкласс.
Вот автономный пример того, что я делаю:
package My::Hello;
sub hello {
my $self =shift;
print "Hello @_\n";
}
package My::Merhaba;
use base 'My::Hello';
sub merhaba {
goto sub { shift->hello(@_) };
}
package main;
My::Merhaba->merhaba('StackOverflow');
Это работает, поскольку я думаю, что это должно и я не видеть, любые проблемы (скажите, если я хотел наследоваться My::Merhaba
: Подклассы ничего не должны знать о merhaba
).
Это было бы лучше/больше корректно для записи
sub merhaba {
my $self = shift;
return $self->hello(@_);
}
Что является преимуществами/недостатками использования goto &NAME
в целях искажения имени метода? Существует ли лучший путь?
Примечание: Если у Вас есть желание ответить goto
является злым, не делают этого потому что это использование Perl goto
отличается, чем, что Вы имеете в виду.
Ваш подход с goto
правильный, потому что он гарантирует, что caller
/ wantarray
и тому подобное будут работать правильно.
Я бы настроил новый метод следующим образом:
sub merhaba {
if (my $method = eval {$_[0]->can('hello')}) {
goto &$method
} else {
# error code here
}
}
Или, если вы не хотите использовать наследование, вы можете добавить новый метод в существующий пакет из вызывающего кода:
*My::Hello::merhaba = \&My::Hello::hello;
# or you can use = My::Hello->can('hello');
тогда вы сможете вызвать:
My::Hello->merhaba('StackOverflow');
и получить желаемый результат.
Любой способ будет работать, путь наследования более удобен, но добавление метода в существующий пакет приведет к более быстрому вызову метода.
Редактировать:
Как было отмечено в комментариях, есть несколько случаев, когда присваивание glob будет нарушать наследование, поэтому, если есть сомнения, используйте первый способ (создание нового метода в подпакете).
Майкл Карман предложил объединить оба метода в самоопределяющуюся функцию:
sub merhaba {
if (my $method = eval { $_[0]->can('hello') }) {
no warnings 'redefine';
*merhaba = $method;
goto &merhaba;
}
die "Can't make 'merhaba' an alias for 'hello'";
}
Вы можете присвоить подпрограммам псевдонимы, манипулируя таблицей символов:
*My::Merhaba::merhaba = \&My::Hello::hello;
Некоторые примеры можно найти здесь .
Я не уверен, какой путь правильный, но Адам Кеннеди использует ваш второй метод (то есть без goto
) в Method :: Alias ( щелкните здесь, чтобы перейти непосредственно к исходному коду ).
Это своего рода комбинация Quick-n-Dirty с небольшим косвенным использованием UNIVERSAL :: can
.
package My::Merhaba;
use base 'My::Hello';
# ...
*merhaba = __PACKAGE__->can( 'hello' );
И в этом пакете у вас будет подзаголовок под названием «merhaba», который имеет псевдоним My :: Hello :: hello
. Вы просто говорите, что все, что этот пакет в противном случае делал бы под именем hello
, он может делать под именем merhaba
.
Однако этого недостаточно, поскольку некоторая часть декоратора кода может изменить подпрограмму, на которую указывает * My :: Hello :: hello {CODE}
. В этом случае Method :: Alias
может быть подходящим способом указать метод, как предполагают молекулы.
Однако, если это довольно хорошо управляемая библиотека, в которой вы управляете как родительскими, так и дочерними категориями, то описанный выше метод более тонкий .