是否可以获取特定Perl类的所有有效方法?

我试图操纵一个类的符号表并获取其所有方法。我发现可以通过$obj->can($method)将子例程与非子例程分开,但这并不能完全按照我的想法进行。

返回以下内容:

subroutine, Property, croak, Group, confess, carp, File

但是,subroutine不是方法(只是一个子例程),并且croakconfesscarp都导入了我的包中。

我真正想要打印的是:
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。 CV中的STASH字段指向定义它的Stash。如您所知,Stash只是一个特殊的哈希(内部表示为HV),因此$cv->STASH返回 B::HV 。如果HV是Stash,而不是常规哈希,则NAMEHV字段包含Stash的标准软件包名称。

现在,我们有了所需的所有信息,可以将所需的程序包名称与coderef的存储名称进行比较。

当然,这是经过简化的,您将需要通过@ISA递归常规类。

没有人喜欢污染的 namespace 。值得庆幸的是,有一些模块可以从存储中删除外来符号,例如namespace::clean。当您正在编译的所有子程序的CV已知时,这没问题。

10-07 19:32
查看更多