如何在Perl中循环遍历类的所有方法?

Bud*_*Joe 9 reflection perl introspection

你如何在Perl中循环所有类的方法?有没有关于Perl内省或反思的在线参考?

Dav*_*sky 13

Todd Gardner给出使用Moose的建议很好,但他选择的示例代码并不是很有帮助.

如果您正在检查非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";
}
Run Code Online (Sandbox Code Playgroud)

有关 如何进行内省的更多详细信息,请参阅Class :: MOP :: Class文档.

你还会注意到我使用了Class :: MOP而不是Moose.Class :: MOP(MOP =元对象协议)是Moose构建的基础.如果您正在使用非Moose课程,使用Moose进行内省并不能获得任何好处.

如果你想,你可以use Moose ()Moose::Meta::Class->initialize不是CMOP.


bri*_*foy 10

您可以使用已提供的答案轻松获取类的已定义方法的列表.但是,Perl是一种动态语言,这意味着可以在以后定义更多方法.实际上没有办法获得任何特定类将处理的所有方法的列表.关于这类东西的更多细节,我在Mastering Perl中有几章.

人们在没有告诉你限制的情况下给你(并且提出)答案.

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";
Run Code Online (Sandbox Code Playgroud)

这里就是我可以打电话给我喜欢的任何方法,另一种情况,但类::督察只返回AUTOLOAD(和人仍下落不明VERSION,isacan):

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";
Run Code Online (Sandbox Code Playgroud)

奇怪的是,每个人似乎都忽略了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";
Run Code Online (Sandbox Code Playgroud)

Class :: MOP具有相同的局限性.

并非每个模块都将使用AUTOLOAD,但它也不是一个模糊或罕见的功能.如果你不介意你会错过一些方法,那么Class :: Inspector或Class :: MOP可能没问题.它不会给你一个列表,列出你可以在每种情况下调用类或对象的每个方法.

如果您有类或对象,并且想要知道是否可以调用特定方法,请使用can().将它包装在一个eval块中,这样可以在那些甚至不是对象的东西上调用can(),在这些情况下仍然可以返回false,而不是死亡:

if( eval { $object->can( 'method_name' ) } )
    {
    $object->( @args );
    }
Run Code Online (Sandbox Code Playgroud)


tre*_*els 5

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

use IO::File;
no strict 'refs';
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::};
Run Code Online (Sandbox Code Playgroud)

散列%{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;
}
Run Code Online (Sandbox Code Playgroud)

有关包和符号表的更多信息,请参阅perlmod手册页.