如何在Perl中循环一个类的所有方法?

如何在Perl中循环一个类的所有方法?,perl,reflection,introspection,Perl,Reflection,Introspection,如何在Perl中循环一个类的所有方法?有关于Perl内省或反射的好的在线参考吗?取决于您是指任何类,还是实现自己的类。对于后者,我使用,它为这些特性提供了非常干净的语法。从食谱中: my %attributes = %{ $self->meta->get_attribute_map }; for my $name ( sort keys %attributes ) { my $attribute = $attributes{$name}; if ( $attribu

如何在Perl中循环一个类的所有方法?有关于Perl内省或反射的好的在线参考吗?

取决于您是指任何类,还是实现自己的类。对于后者,我使用,它为这些特性提供了非常干净的语法。从食谱中:

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

在一般情况下,您必须检查符号表(除非您使用Moose)。例如,要列出在
IO::File
包中定义的方法:

use IO::File;
no strict 'refs';
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::};
hash
%{IO::File::}
IO::File包
的符号表,而
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;
}

有关软件包和符号表的更多信息,请参见手册页。

托德·加德纳(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而不是Moose。MOP(MOP=元对象协议)是Moose构建的基础。如果你使用的是非驼鹿类课程,那么使用驼鹿进行内省并不会给你带来任何好处


如果需要,您可以
使用Moose()
Moose::Meta::Class->initialize
而不是CMOP。

您可能需要Class::Inspector->methods('Your::Class')


Nuff说。

使用已经提供的答案,您可以很容易地获得一个类的已定义方法列表。然而,Perl是一种动态语言,这意味着以后可能会定义更多的方法。实际上,没有办法获得任何特定类将要处理的所有方法的列表。关于这类东西的更多细节,我在后面有几章

人们给你(和投票)的答案没有告诉你限制

Adam提到了他的方法,但它并没有真正起作用,因为它试图做一些动态语言不能做的事情(这是静态的:),例如,这里有一个片段,其中Class::Inspector不返回任何方法,但我仍然可以调用
版本
方法(以及
isa
can
):

这里还有一个例子,我可以调用我喜欢的任何方法,但是Class::Inspector只返回
自动加载
(仍然缺少
版本
isa
,和
can
):

奇怪的是,每个人似乎都忽略了UNIVERSAL,可能是因为他们没有明确地处理它,因为它实际上只存在于@ISA中。我可以向每个类添加一个
debug
方法,而class::Inspector仍然会忽略它,即使它是一个已定义的方法:

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::Inspector或Class::MOP可能没问题。它不会给出在任何情况下都可以调用类或对象的每个方法的列表

如果您有一个类或对象,并且希望知道是否可以调用特定的方法,请使用can()。将其包装在一个eval块中,这样can就可以对甚至不是对象的对象调用can(),在这些情况下仍然返回false,而不是death:

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

我会把这个放在这里等我忘了的时候。这是非常强大的,;遗憾的是,它太偏僻了,以至于大多数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::;

对于第一个问题,请参见:注意,除非您要内省的类首先是使用Moose定义的,否则Moose将找不到任何属性。但是,方法内省以及其他大部分功能都可以正常工作。+1:太好了,我不知道你可以这样使用Class::MOP。我在回答中解释了它的局限性。即使是空类,它也无法从UNIVERSAL中提取方法,也无法从AUTOLOAD中提取任何方法。@brian d foy:使用AUTOLOAD很糟糕,mmmkay?不是每个方法都必须在符号表中定义,而且您缺少UNIVERSAL。我想知道,这个问题的任何解决方案,尤其是这里的解决方案,每次调用代码时生成一个新的对象实例,如果代码被回收,或者每个实例都留在内存中,直到程序终止。因为在某些其他语言(如.NET和Java)中使用反射/内省时,必须小心实例化类对象引用的位置,否则每次调用都会得到新实例。
if( eval { $object->can( 'method_name' ) } )
    {
    $object->( @args );
    }
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::;