2012-06-03 70 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

相關問題