是否可以获得特定 Perl 类的所有有效方法?
我正在尝试操作一个类的符号表并获取它的所有方法。我发现我可以通过 $obj->can($method)
将子程序与非子程序分开。 ,但这并不完全符合我的想法。
以下返回:
subroutine, Property, croak, Group, confess, carp, File
但是,
subroutine
不是一种方法,(只是一个子程序)和croak
, confess
, 和 carp
都导入到我的包中。我真正想打印的是:
Property,Group, File
但我会采取:
subroutine, Property,Group, File
下面是我的程序:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my $sections = Section_group->new;
say join ", ", $sections->Sections;
package Section_group;
use Carp;
sub new {
return bless {}, shift;
}
sub Add {
my $self = shift;
my $section = shift;
}
sub Sections {
my $self = shift;
my @sections;
for my $symbol ( keys %Section_group:: ) {
next if $symbol eq "new"; # This is a constructor
next if $symbol eq "Add"; # Not interested in this method
next if $symbol eq "Sections"; # This is it's own method
push @sections, $symbol if $self->can($symbol);
}
return wantarray ? @sections : \@sections;
}
sub subroutine {
my $param1 = shift;
my $param2 = shift;
}
sub Group {
my $self = shift;
my $section = shift;
}
sub File {
my $self = shift;
my $section = shift;
}
sub Property {
my $self = shift;
my $section = shift;
}
最佳答案
这是相当微不足道的。我们只想保留那些最初在我们的包中定义的子名称。每个 CV(代码值)都有一个指向定义它的包的指针。感谢 B
,我们可以检查:
use B ();
...
if (my $coderef = $self->can($symbol)) {
my $cv = B::svref_2object $coderef;
push @sections, $symbol if $cv->STASH->NAME eq __PACKAGE__;
}
# Output as wanted
也就是说,我们使用
svref_2object
执行自省(introspection)。 .这将返回一个表示内部 perl 数据结构的 Perl 对象。如果我们查看 coderef,我们会得到
B::CV
object ,代表内部CV . STASH
CV 中的字段指向定义它的 Stash。如您所知,一个 Stash 只是一个特殊的哈希(内部表示为 HV ),所以 $cv->STASH
返回 B::HV
. NAME
HV
的字段如果 HV 是 Stash,而不是常规哈希,则包含 Stash 的完全限定包名称。现在我们有了我们需要的所有信息,并且可以将想要的包名称与 coderef 的存储名称进行比较。
当然,这是简化的,您将希望通过
@ISA
进行递归。普通类。没有人喜欢被污染的命名空间。值得庆幸的是,有些模块可以从 Stash 中删除外来符号,例如
namespace::clean
.当您调用的所有子程序的 CV 在编译时已知时,这没有问题。
关于perl - 是否可以获得特定 Perl 类的所有有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18390256/