2012-06-03 64 views

回答

9

不是。

TL; DR:

  • 你可以找到明确声明或置入对象的类的命名空间子程序的名字。

  • 你无法区分这些子程序是你的对象对象的方法,哪些是类或非对象潜艇(这是那些上市中最严重的问题/ limintation)。

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

    这可以通过检查@ISA的类为build 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 
    

    注:由于事实上,一些人居然写自己的类的方法 - 那些能够以这种方式工作 - 在明确工作的所有3(或第一2)个案,不管该方法如何被调用。

+0

*“除非已经在对象上调用了对象,否则不能从超类的子类中找到对象所继承的方法”*。如果我正确地阅读了你的话,你应该说'$ obj-> inherited_method'必须运行才能找到'inherited_method'?我不认为这是真的,或[这些perl5i测试](https://metacpan.org/source/MSCHWERN/perl5i-v2.9.1/t/Meta/methods.t)不起作用。有代码来支持? – Schwern

+0

@Schwern - 请参阅该子句中的第二句:“可以通过检查类的ISA来构建继承树或使用适当的CPAN模块来编码。” “不能”部分指的是直接读取命名空间哈希的上述总结技术。这个备份代码(比你读的更少),是我在答案中的代码。 – DVK

+0

哦。我只是把'@ ISA'作为一个给定的行走。 – Schwern

0

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

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

use perl5i::2; 

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

至少消除了很多代码。

+0

'方法'如何区分对象的方法和类的非对象子(参见第3部分中的3个示例)? POD似乎对此没有任何澄清。 – DVK

+0

另外,它是否正确处理AUTOLOAD的东西? – DVK

+0

@DVK简单:没有。正如你正确指出的那样,它不能。它只是列出了所有继承步行和符号表检查的可用的具体可调用方法,因此您不必这样做。我会在我的答案中更正一些代词,使其更清楚。它*可以利用perl5i的func/method区分优势,但它目前不能。 – Schwern

相关问题