Во-первых, вы, вероятно, должны croak
вместо того, чтобы молча ничего не делать, потому что, согласно вашим спецификациям, вызов foo
в качестве метода класса является нарушением договора.
Во-вторых, достаточно просто проверить, является ли первый аргумент ссылкой. Ваш метод потерпит неудачу, если задействовано наследование:
#!/usr/bin/perl
package A;
use Carp;
sub new { bless {} => shift }
sub foo {
croak "I am not in " . __PACKAGE__ unless __PACKAGE__ eq ref(shift)
}
package B;
use base 'A';
package main;
$x = B->new;
$x->foo;
C:\Temp> t
I am not in A at C:\Temp\t.pl line 19
См. Также perldoc -f ref :
Если указанный объект был благословлен в пакет, то вместо этого возвращается имя этого пакета. Вы можете думать о ref
как о typeof
операторе.
Итак:
sub foo {
croak "Don't call as class method" unless ref shift;
}
Наконец, обратите внимание, что ref
никогда возвращает undef
.
Хорошо ли добавлять эту проверку в каждый метод? Я полагаю, что этот аргумент можно сделать из дизайна в виде контракта.
С другой стороны, мои методы предполагают, что они были вызваны как методы экземпляра, и я проверяю только возможность вызова метода в качестве метода класса, если метод может обеспечить значимое альтернативное поведение при вызове как таковое.
Я не могу вспомнить ни одного модуля, у которого есть такие проверки.
Кстати, вместо
sub foo {
my ($self) = @_;
вы должны использовать
sub foo {
my $self = shift;
оставляя только аргументы метода в @_
для распаковки. Или вы должны распаковать все аргументы одним махом:
sub foo {
my ($self, $bar, $baz) = @_;