有没有办法知道Perl中未知类的实例的方法

有没有办法知道Perl中未知类的实例的方法,perl,object,Perl,Object,我有一个Perl程序,它使用我从另一个来源获得的包。该方法的一个函数返回一个未知类的对象,我有没有办法在不查看对象的类实现的情况下获取对象的所有可能方法?不太可能 TL;医生: 您可以找到显式声明或放置在对象类命名空间中的子例程的名称 您无法区分这些子例程中哪些是对象上的对象方法,哪些是类或非对象子例程(这是列出的子例程中最严重的问题/缺陷) 使用此方法,无法在子类中找到对象从超类继承的方法,除非已对对象调用了这些方法 这可以通过检查类的@ISA来进行编码 您找不到动态添加到类中的方法(自动加

我有一个Perl程序,它使用我从另一个来源获得的包。该方法的一个函数返回一个未知类的对象,我有没有办法在不查看对象的类实现的情况下获取对象的所有可能方法?

不太可能

TL;医生:

  • 您可以找到显式声明或放置在对象类命名空间中的子例程的名称

  • 您无法区分这些子例程中哪些是对象上的对象方法,哪些是类或非对象子例程(这是列出的子例程中最严重的问题/缺陷)

  • 使用此方法,无法在子类中找到对象从超类继承的方法,除非已对对象调用了这些方法

    这可以通过检查类的
    @ISA
    来进行编码

  • 您找不到动态添加到类中的方法(自动加载,在代码中的某个地方手动注入方法)

详细信息

  • 您可以找到该类中的所有子例程(通过结合类名称空间是散列的事实,使其中的所有标识符都是该散列中的键;以及
    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
    ,但不是
    x1
    y2
    ——因为
    new
    已执行且
    z3
    已在类中声明;但是
    x1
    y2
    都不是,它们只是理论上继承的。但是,一旦我们执行了继承的
    x1
    方法,第二个时间列表就包含了它,但仍然缺少继承的
    y2


  • 但不幸的是,您无法区分作为对象方法的子例程(例如,将它获取的第一个参数视为对象)、类方法(例如,将它获取的第一个参数视为类名)或非OO子例程(将第一个参数视为常规参数)

    要区分这三种语言,唯一的方法是对代码进行语义分析。否则,您无法区分:

    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种)情况下工作,而不管如何调用该方法


  • DVK的答案是准确的,但有点冗长。简单的回答是可以,但您不知道什么是作为公共对象方法的,什么不是。可能会显示从其他模块导入的私有方法和函数

    获取可调用的具体(即非自动加载)方法列表的最简单方法是使用的方法


    这至少消除了大量代码。

    “您无法在子类中找到对象从超类继承的方法,除非它们已经在您的对象上被调用”。如果我没看错的话,你是说必须先运行
    $obj->inherited\u方法
    ,然后才能发现
    inherited\u方法
    ?我不认为这是真的,也不可能奏效。有代码支持吗?@Schwern-参见该项目符号中的第二句话:“这可以通过检查类的ISA来构建继承树,或者使用适当的CPAN模块来进行编码。”。“cannot”部分指的是上面总结的直接读取名称空间散列的技术。这个语句的备份代码(没有你读过的那么夸张)是我在答案中的代码。我只是把walking
    @ISA
    作为一个例子。
    方法如何区分对象的方法和类的非对象子类(参见第2部分中的3个示例)?POD似乎对此没有任何澄清。@DVK Simple:没有。正如你正确指出的,它不能。它只是列出了执行所有继承遍历和符号表检查的可用的、具体的、可调用的方法,所以您不必这样做。我将更正我答案中的几个代词,使之更清楚。它可以利用perl5i的func/method特性,但目前没有。您介意我将“方法列表”编辑为“子例程列表(方法与否)”吗?在具有OO功能的语言中,@DVK.:)
    
    use perl5i::2;
    
    my $object = Something::Something->new;
    my @methods = $object->mo->methods;