2009-06-20 76 views
9

如何遍歷Perl中所有類的方法?是否有任何良好的在線引用Perl內省或反思?如何循環遍歷Perl中所有類的方法?

+0

對於第一個問題,請參閱:http://stackoverflow.com/questions/910430/how-do-i-list-available-methods-on-a-given-object-or-package-in -perl – molf 2009-06-20 14:47:38

回答

13

Todd Gardner給出的使用Moose的建議是一個不錯的選擇,但他選擇的示例代碼並不是很有幫助。

如果您使用類檢查非穆斯,你會做這樣的事情:

use Some::Class; 
use Class::MOP; 

my $meta = Class::MOP::Class->initialize('Some::Class'); 

for my $meth ($meta->get_all_methods) { 
    print $meth->fully_qualified_name, "\n"; 
} 

關於如何做反省;詳情請參閱Class::MOP::Class docs

你還會注意到我使用了Class :: MOP而不是Moose。 Class :: MOP(MOP =元對象協議)是Moose構建的基礎。如果你正在與非穆斯類一起工作,使用穆斯來反思並不會給你帶來任何好處。

如果你願意,你可以用use Moose()Moose::Meta::Class->initialize代替CMOP。

3

取決於你的意思,任何課程,或者如果你正在實施你自己的。對於後者,我使用Moose,它爲這些功能提供了非常乾淨的語法。從食譜:

my %attributes = %{ $self->meta->get_attribute_map }; 
for my $name (sort keys %attributes) { 
    my $attribute = $attributes{$name}; 

    if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled') 
    # ... keeps on 
+0

請注意,Moose不會找到任何屬性,除非您首先使用Moose定義了自反類。 但是,方法內省以及其他大部分位都可以正常工作。 – 2009-06-20 19:47:40

5

在一般情況下,你必須檢查符號表(除非你用麋)。例如,以列出IO::File包中定義的方法:

use IO::File; 
no strict 'refs'; 
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::}; 

散列%{IO::File::}IO::File package的符號表,以及grep過濾掉非子程序條目(例如包變量)。

若要擴展此以包含繼承方法,您必須遞歸搜索父類的符號表(@IO::File::ISA)。

下面是一個完整的例子:

sub list_methods_for_class { 
    my $class = shift; 
    eval "require $class"; 
    no strict 'refs'; 
    my @methods = grep { defined &{$class . "::$_"} } keys %{$class . "::"}; 
    push @methods, list_methods_for_class($_) foreach @{$class . "::ISA"}; 
    return @methods; 
} 

有關包和符號表的詳細信息,請參閱perlmod手冊頁。

+0

並非每個方法都必須在符號表中定義,並且您缺少UNIVERSAL。 – 2009-06-21 13:17:44

+0

我想知道,如果這個問題的任何解決方案,特別是這裏的這個問題,每次調用代碼時都會生成一個新的對象實例,並且在程序終止之前它會被回收或每個實例停留在內存中。因爲在.NET和Java等其他語言中使用反射/自省,必須小心在哪裏實例化類對象引用,否則每次調用都可以獲得新實例。 – David 2012-12-24 07:55:37

3

您可能需要Class :: Inspector->方法('Your :: Class')。

Nuff說。

10

使用已經提供的答案,您可以輕鬆地獲得已定義方法的列表。但是,Perl是一種動態語言,這意味着更多的方法可能會在以後定義。實際上沒有辦法獲得任何特定類將處理的所有方法的列表。有關這類內容的更多細節,我在Mastering Perl中有幾章。

人們給你(和upvoting)的答案,而不告訴你的限制。

Adam提到他的Class::Inspector,但它並沒有真正的工作,因爲它試圖做一些動態語言不能做的事情(這是靜態的:)例如,這是一個片段,其中Class :: Inspector不返回任何方法,但我仍然可以調用VERSION方法(以及isacan):

BEGIN { 

package Foo; 

our $VERSION = '1.23' 
} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # reports nothing 

print Foo->VERSION, "\n"; 

這裏就是我可以打電話給我喜歡的任何方法,另一種情況,但類::督察只返回AUTOLOAD(現在仍然失蹤VERSIONisacan):

BEGIN { 

package Foo; 

our $VERSION = '1.23'; 

my $object = bless {}, __PACKAGE__; 

sub AUTOLOAD { $object } 

} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # reports only "AUTOLOAD" 

print Foo->dog->cat->bird, "\n"; 

奇怪的是,每個人似乎都忽略了UNIVERSAL,可能是因爲他們沒有明確地處理它,因爲它實際上只是在@ISA中。我可以添加一個debug方法每一個類和類::督察還惦記着它,即使它是一個定義的方法:

BEGIN { 

sub UNIVERSAL::debug { "Hello debugger!\n" }  
package Foo; 
} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # still reports nothing 

print Foo->debug, "\n"; 

Class::MOP具有相同的限制。

並非每個模塊都將使用AUTOLOAD,但它也不是一個晦澀或罕見的功能。如果你不介意你會錯過一些方法,那麼Class :: Inspector或Class :: MOP可能沒問題。這不會給你一個每種方法的清單,你可以在任何情況下調用一個類或一個對象。

如果您有一個類或一個對象,並且想知道是否可以調用某個特定方法,請使用can()。包裝在一個eval塊所以可以調用可以()上的東西,甚至沒有對象仍找回假的,而不是死亡,在這些情況下:

if(eval { $object->can('method_name') }) 
    { 
    $object->(@args); 
    } 
0

我就離開這個這裏當我忘記它。這是非常強大的;太糟糕了,大多數Perl程序員都從來沒有體驗過它。

package Foo; 
use strict; 
sub foo1 {}; 
sub foo2 {}; 
our $foo3 = sub{}; 
my $foo4 = "hello, world!"; 

package Bar; 
use strict; 

# woo, we're javascript! 
(sub { 
    *Bar::foo1 = sub { print "hi!"; }; 
    *Bar::foo2 = sub { print "hello!"; }; 
    $Bar::foo1 = 200; 
})->(); 

package main; 
use strict; 
use Data::Dumper;  
$Data::Dumper::Deparse = 1; 

print Dumper \%Data::Dumper::; 
print Dumper \%Foo::; 
print Dumper \%Bar::;