是否有可能获得特定Perl类的所有有效方法?
我试图操纵类的符号表并获取其所有方法.我发现我可以通过$obj-> can($method)从非子程序中分离出子程序,但这并不能完全符合我的想法.
以下返回:
subroutine,Property,croak,Group,confess,carp,File
但是,子程序不是一个方法,(只是一个子程序),并且croak,confess和carp都被导入到我的包中.
我真正想要打印的是:
Property,File
但我会接受:
subroutine,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执行内省.这将返回表示内部perl数据结构的Perl对象.
如果我们查看coderef,我们得到一个B::CV
object,它代表内部CV.CV中的STASH字段指向定义它的Stash.如您所知,Stash只是一个特殊的哈希(内部表示为HV),因此$cv-> STASH返回B::HV
.如果HV是a,则HV的NAME字段包含Stash的完全限定包名称存储,而不是常规哈希.
现在我们拥有了所需的所有信息,并且可以将所需的包名称与coderef的存储名称进行比较.
当然,这是简化的,你会希望通过@ISA递归一般课程.
没有人喜欢受污染的命名空间.值得庆幸的是,有些模块可以从Stash中删除外来符号,例如:命名空间::干净.当您调用的所有子函数的CV在编译时已知时,这没有问题.