Как проверить, была ли вызвана подпрограмма с помощью метода вызова объекта или нет

#perl #object #subroutine #method-invocation

#perl #объект #подпрограмма #метод-вызов

Вопрос:

Вы можете вызвать подпрограмму как метод, используя два синтаксиса в примере ниже.

Но вы также можете вызвать ее не как объект.

 #====================================================
package Opa;
sub opa{
    $first= shift;
    $second= shift;
    print "Opa $first -- $secondn";
}

package main;
# as object:
Opa->opa("uno");
opa Opa ("uno");
# not as object
Opa::opa("uno","segundo");
Opa::opa("Opa","uno");
#====================================================
  

Есть ли способ изнутри подпрограммы узнать «в целом», какой вызов получил sub ?.

Комментарии:

1. Зачем вам это знать? Это звучит как xy-проблема.

Ответ №1:

Вы можете использовать called_as_method from Devel::Caller .

 use Devel::Caller qw( called_as_method );
sub opa{
    print called_as_method(0) ? 'object: ' : 'class: ';
    $first= shift;
    $second= shift;
    print "Opa $first -- $secondn";
}
  

Вывод:

 object: Opa Opa -- uno
object: Opa Opa -- uno
class: Opa uno -- segundo
class: Opa Opa -- uno
  

Ответ №2:

Вы также можете сделать это с ref() помощью функции вместо использования внешних модулей:

 use warnings;
use strict;

package Test;

sub new {
    return bless {}, shift;
}
sub blah {
    if (ref $_[0]){
        print "method calln";
    }
    else {
        print "class calln";
    }
}

package main;

my $obj = Test->new;

$obj->blah;
Test::blah;
  

Вывод:

 method call
class call
  

Комментарии:

1. Подпрограммы могут принимать ссылки в качестве аргументов, так как это ненадежно для обнаружения вызова метода. Но ref() предоставляет больше: используйте его, чтобы проверить, предоставляет ли ref($_[0]) имя класса / пакета: if (ref($_[0]) eq PACKAGE ) { … }

2. [ Укушено Markdown: это два символа подчеркивания, объединенные с ‘PACKAGE’, объединенным с еще двумя символами подчеркивания. ]