5

別のソースから入手したパッケージを使用するPerlのプログラムがあります。メソッドの関数の1つは、未知のクラスのオブジェクトを返します。クラスの実装を見ずに、オブジェクトのすべての可能なメソッドを取得する方法はありますか?

4

2 に答える 2

9

あまり。

TL; DR:

  • オブジェクトのクラスの名前空間に明示的に宣言または配置されたサブルーチンの名前を見つけることができます。

  • これらのサブルーチンのどれがオブジェクトのオブジェクトメソッドであり、どれがクラスまたは非オブジェクトサブルーチンであるかを区別することはできません(これは、リストされているものの中で最も深刻な問題/制限です)。

  • オブジェクトで既に呼び出されていない限り、このメソッドを使用してスーパークラスからサブクラス内のオブジェクトによって継承されたメソッドを見つけることはできません。

    @ISAこれは、クラスを調べて継承ツリーを構築するか、適切なCPANモジュールを使用することでコーディングできます。

  • クラスに動的に追加されるメソッドが見つかりません(AUTOLOAD、コード内の手動メソッドインジェクションのどこかにあります)。

詳細に

  1. そのクラスのすべてのサブルーチンを見つけることができます(クラスの名前空間がハッシュであるため、その中のすべての識別子がそのハッシュのキーであるという事実と、UNIVERSAL::can個別のサブルーチンの呼び出しを組み合わせることによって)。

    したがって、クラス内のサブルーチンの100%がオブジェクトメソッドであり、クラスがサブクラスではないことが(技術的でない契約によって)保証されている場合は、それらのリストを見つけることができます。

    package MyClass;
    use vars qw($z5);
    my $x = 11; our $y = 12; $z5 = 14; %z2 = (1=>2); # my, our, globals, hash
    sub new { return bless({}, $_[0]) }; # Constructor
    sub x1 { my $self = shift; print $_[0]; };
    sub y2  { my $self = shift; print $_[0]; };
    ##############################################################################
    package MySubClass;
    use vars qw(@ISA);
    @ISA = ("MyClass");
    sub z3 { return "" };
    ##############################################################################
    package main;
    use strict; use warnings;
    
    my $obj = MyClass->new();
    list_object_methods($obj);
    my $obj2 = MySubClass->new();
    list_object_methods($obj2);
    $obj2->x1();
    list_object_methods($obj2); # Add "x1" to the list!
    
    sub list_object_methods {
        my $obj = shift;
        my $class_name = ref($obj);
        no strict;
        my @identifiers = keys %{"${class_name}::"};
        use strict;
        my @subroutines = grep { UNIVERSAL::can($obj, $_) } @identifiers;
        print "Class: ${class_name}\n";
        print "Subroutines: \n=========\n"
            . join("\n", sort @subroutines) . "\n=========\n";
    }
    

    ...プリント:

    Class: MyClass
    Subroutines:
    =========
    new
    x1
    y2
    =========
    Class: MySubClass
    Subroutines:
    =========
    new
    z3
    =========
    Class: MySubClass
    Subroutines:
    =========
    new
    x1
    z3
    =========
    

    初回リスト(MySubClassの場合)は印刷されnewますが、実行されてクラスで宣言されたため、または-ではz3ないことに注意してください。しかし、どちらでもありませんでした-それらは単に理論的に継承されただけです。しかし、継承されたメソッドを実行すると、2回目のリストにはそれが含まれていましたが、継承されたメソッドはまだありません。x1y2newz3x1y2x1y2


  2. ただし、残念ながら、オブジェクトメソッド(たとえば、取得した最初の引数をオブジェクトとして扱う)、クラスメソッド(たとえば、取得した最初の引数をクラス名として扱う)、またはOO以外のサブルーチンであるサブルーチンを区別することはできません。 (最初の引数を通常の引数として扱います)。

    3つを区別するための唯一の方法は、実際にコードを意味的に分析することです。そうしないと、次の違いがわかりません。

    sub s_print_obj {
        my ($self, $arg1) = @_;
        $s->{arg1} = $arg1;
        print "$arg1\n";
    }
    # $obj->s_print_obj("XYZ") prints "XYZ" and stores the data in the object
    
    sub s_print_class {
        my ($class, $arg1) = @_; 
        print "Class: $class\n";
        print "$arg1\n";
    }
    # $obj->s_print_class("XYZ") prints "Class: MyClass\nXYZ\n"
    
    sub s_print_static {
        my ($self, $arg1) = @_;
        print "$arg1\n";
    }
    # $obj->s_print_static("XYZ") prints stringified representation of $obj
    

    注:実際のところ、メソッドがどのように呼び出されても、3つすべて(または最初の2つ)の場合に明示的に機能するように、クラスのメソッド(このように機能するメソッド)を実際に作成する人もいます。

于 2012-06-03T10:54:08.800 に答える
0

DVKの答えは正確ですが、少し長いです。簡単な答えは「はい」ですが、パブリックオブジェクトメソッドとして何が意図されていて、何が意図されていなかったかはわかりません。他のモジュールからインポートされたプライベートメソッドと関数が表示される場合があります。

呼び出し可能な具体的な(つまり、非AUTOLOAD)メソッドのリストを取得する最も簡単な方法は、perl5iメタオブジェクトmethods()メソッドを使用することです。

use perl5i::2;

my $object = Something::Something->new;
my @methods = $object->mo->methods;

それは少なくとも多くのコードを排除します。

于 2012-06-03T17:22:48.747 に答える