是否有可能获得特定Perl类的所有有效方法?

Dav*_* W. 6 oop methods perl class

是否有可能获得特定Perl类的所有有效方法?

我试图操纵类的符号表并获取其所有方法.我发现我可以通过它从非子程序中分离出子程序$obj->can($method),但这并不完全符合我的想法.

以下返回:

subroutine, Property, croak, Group, confess, carp, File
Run Code Online (Sandbox Code Playgroud)

但是,subroutine是不是方法,(只是一个子程序),并且croak,confesscarp全部导入到我的包.

我真正想要打印的是:

Property,Group, File
Run Code Online (Sandbox Code Playgroud)

但我会接受:

subroutine, Property,Group, File
Run Code Online (Sandbox Code Playgroud)

以下是我的计划:

#! /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;
}
Run Code Online (Sandbox Code Playgroud)

amo*_*mon 6

这是相当微不足道的.我们只想保留最初在我们的包中定义的子名称.每个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
Run Code Online (Sandbox Code Playgroud)

也就是说,我们使用进行内省svref_2object.这将返回表示内部perl数据结构的Perl对象.

如果我们查看coderef,我们会得到一个B::CV对象,它代表内部CV.STASHCV中的字段指向定义它的Stash.如您所知,Stash只是一个特殊的哈希(内部表示为HV),因此$cv->STASH返回一个B::HV.如果HV是Stash,则a 的NAME字段HV包含Stash的完全限定包名,而不是常规哈希.

现在我们拥有了所需的所有信息,并且可以将所需的包名称与coderef的存储名称进行比较.

当然,这是简化的,您将需要递归@ISA一般类.


没有人喜欢受污染的命名空间.值得庆幸的是,有一些模块可以从Stash中删除外来符号,例如namespace::clean.当您调用的所有子函数的CV在编译时已知时,这没有问题.

  • 然后,有时人们实际上从另一个包中导入一个方法(例如`使用Exporter'import';`而不是`@ISA = qw(Exporter);`). (3认同)

bri*_*foy 6

你想做什么?为什么类如何定义或实现它响应的方法?

Perl是一种动态语言,因此这意味着方法根本不存在.使用AUTOLOAD,方法可能非常精细和可调用,但永远不会出现在符号表中.一个好的界面可以can在这些情况下工作,但是可能存在一个类或一个对象决定用false来响应它的情况.

套票:藏匿模块可以帮助你找到一个特定的命名空间中定义的子程序,但就像你说的,他们可能不会在同一个文件中定义.类中的方法可能来自继承的类.如果你关心他们来自哪里,你可能做错了.