是否可以为特定的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;
}
答案 0 :(得分: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
也就是说,我们使用svref_2object
执行内省。这将返回一个表示内部perl数据结构的Perl对象。
如果我们查看coderef,我们会得到B::CV
object,它代表内部CV。 CV中的STASH
字段指向定义它的Stash。如您所知,Stash只是一个特殊的哈希(内部表示为HV),因此$cv->STASH
会返回B::HV
。如果HV是Stash,则NAME
的{{1}}字段包含Stash的完全限定包名称,而不是常规哈希。
现在我们拥有了所需的所有信息,并且可以将所需的包名称与coderef的存储名称进行比较。
当然,这是简化的,您需要通过HV
递归一般课程。
没有人喜欢受污染的命名空间。值得庆幸的是,有一些模块可以从Stash中删除外来符号,例如: @ISA
。当您调用的所有子函数的CV在编译时都已知时,这没有问题。
答案 1 :(得分:6)
你想做什么?为什么类如何定义或实现它响应的方法?
Perl是一种动态语言,因此这意味着方法根本不存在。使用AUTOLOAD
,方法可能非常精细且可调用,但从不显示在符号表中。一个好的接口会使can
在这些情况下起作用,但可能会出现类或对象决定用false响应的情况。
Package::Stash模块可以帮助您在特定命名空间中查找已定义的子例程,但正如您所说,它们可能未在同一文件中定义。类中的方法可能来自继承的类。如果你关心他们来自哪里,你可能做错了。