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

时间:2012-06-03 10:21:17

标签: perl object

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

2 个答案:

答案 0 :(得分:9)

不是。

TL; DR:

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

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

  • 您无法使用此方法找到超类中子对象继承的方法,除非已在您的对象上调用它们。

    这可以通过检查班级@ISAbuild up inheritance trees, or using on of proper CPAN modules来编码。

  • 您无法找到动态添加到类中的方法(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)打印newz3但不是x1y2 - 因为new已执行且课堂上宣布z3;但是x1y2都不是 - 它们只是理论上的继承。但是,一旦我们执行了继承的x1方法,那么第二次列表就会包含它,但仍然缺少继承的y2


  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
    

    注意:事实上,有些人实际上写了他们班级的方法 - 那些可以这样工作的方法 - 明确地在ALL 3(或前2)的情况下工作,无论方法如何被调用。

答案 1 :(得分:0)

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

获取可调用,具体(即非AUTOLOAD)方法列表的最简单方法是使用perl5i meta objectmethods()方法。

use perl5i::2;

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

这至少消除了很多代码。