2009-06-20 78 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::;