2013-08-22 98 views
6

是否有可能獲得特定Perl類的所有有效方法?是否有可能爲特定的Perl類獲取所有有效的方法?

我想操縱一個類的符號表並獲得它的所有方法。我發現我可以通過$obj->can($method)從非子程序中分離出子程序,但這並不完全符合我的想法。

以下回報:

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

然而,subroutine不是方法,(只是一個子程序),並croakconfess,並都導入到我的包。

我真正想要打印的是:

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; 
} 

回答

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::HVHVNAME字段包含HV爲Stash且不是常規散列的Stash的完全限定軟件包名稱。

現在我們有我們需要的所有信息,並且可以比較想要的包名稱和coderef的存儲名稱。

當然,這是簡化的,你會想通過@ISA一般類的遞歸。


沒有人喜歡污染的命名空間。值得慶幸的是,有一些模塊可以從存儲器中移除外來符號,例如namespace::clean。在編譯時知道所有正在調用的子程序的CV時,這是沒有問題的。

+3

然後,有時候人們實際上會從另一個包中導入一個方法(例如'使用Exporter'import';'而不是'@ISA = qw(Exporter);')。 – cjm

+0

@cjm當然,但我想這不會經常發生,甚至可能是反模式。希望大多數人能夠從OOP(它解決了許多命名空間問題)中精心分離程序性編程(包括導入)。沒有辦法知道導入的sub是否意味着成爲一種方法,所以這必須足夠好。 (等等,也許我們可以訪問':method'屬性......) – amon

+0

_這很簡單。不重要的?你在週末建造超快速發電機? Pervoc on ** svref_2object **:_引用任何Perl值,並將引用值轉換爲適當的B :: OP派生類或B :: SV派生類中的對象._我不知道什麼這是在談論。但是,它確實有效。我想現在是時候深入研究以前未發表的內容,並更多地改進我的Perl遊戲。要麼,要麼學習Python。 –

6

你想做什麼?爲什麼一個類如何定義或實現它所響應的方法?

Perl是一種動態語言,所以這意味着方法根本不必存在。與AUTOLOAD,一種方法可能是完美的,可調用的,但從不出現在符號表中。一個好的界面會使can在這些情況下工作,但可能會出現類或對象決定用false來響應的情況。

Package::Stash模塊可以幫助您在特定命名空間中查找已定義的子例程,但正如您所說,它們可能未在同一個文件中定義。類中的方法可能來自繼承的類。如果你關心他們來自哪裏,你可能做錯了。

+0

我有一個名爲_Sections_的類,它表示我的控制文件中的各種節類型,它是Windows INI格式。每個部分都有參數,但參數對於每種類型的部分都不相同。 (目前有五個)。每種類型的部分都是部分的子類。我有另一個班,爲我保存所有各個部分列表。每個部分類型在最後一個類中都有一個新的方法。這樣,我對該INI文件的整個定義就在一個對象中。我班上的一種方法讓我知道所有其他子類的名稱。 –

+0

我曾經使用AUTOLOAD,但現在我避免它。使用'嚴格'使編程更好。使用參考結構可消除該安全性。我可能在一個地方有'$ foo - > {BAR}',另一個地方可能有'$ foo - > {BRA}',嚴格的'不能'接受。 OO放棄這種安全。如果我的方法是$ foo-> Bar,調用$ foo-> Bra會使我的程序崩潰。 AUTOLOAD打破了這種設計。兩者現在都是真正的方法。它也適用於較差的整體設計。我可以用AUTOLOAD來做它。我不必思考問題。我的這個程序的prev版本使用了AUTOLOAD,由於AUTOLOAD,它很難調試。 –

+0

我會添加所有解釋到這個問題:) –

相關問題