2013-08-22 32 views
6

Có thể nhận tất cả các phương thức hợp lệ cho một lớp Perl cụ thể không?Có thể nhận tất cả các phương thức hợp lệ cho một lớp Perl cụ thể không?

Tôi đang cố gắng thao tác bảng biểu tượng của một lớp và nhận tất cả các phương pháp của nó. Tôi tìm thấy tôi có thể tách ra các chương trình con từ các chương trình con không thông qua các $obj->can($method), nhưng điều đó không làm chính xác những gì tôi nghĩ rằng nó.

Lợi nhuận sau:

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

Tuy nhiên, subroutine không phải là một phương pháp, (chỉ là một chương trình con), và croak, confess và đều được nhập khẩu vào gói của tôi.

Những gì tôi thực sự muốn in ra là:

Property,Group, File 

Nhưng tôi sẽ thực hiện:

subroutine, Property,Group, File 

Dưới đây là chương trình của tôi:

#! /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; 
} 

Trả lời

6

này là khá tầm thường. Chúng tôi chỉ muốn giữ những tên phụ đã được định nghĩa ban đầu trong gói của chúng tôi. Mỗi CV (giá trị mã) có một con trỏ tới gói mà nó được định nghĩa. Nhờ B, chúng ta có thể xem xét rằng:

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 

Đó là, chúng tôi thực hiện mẫn sử dụng svref_2object. Điều này trả về một đối tượng Perl đại diện cho một cấu trúc dữ liệu perl nội bộ.

Nếu chúng ta nhìn vào một coderef, chúng tôi nhận được một B::CV object, đại diện cho nội bộ CV. Trường STASH trong một điểm CV tới Stash nơi nó được xác định. Như bạn đã biết, Stash chỉ là một băm đặc biệt (được biểu thị bên trong là HV), do đó, $cv->STASH trả về một B::HV. Trường NAME của HV chứa tên gói đầy đủ của Stash nếu HV là Stash và không phải là băm thông thường.

Bây giờ chúng tôi có tất cả thông tin chúng tôi cần và có thể so sánh tên gói mong muốn với tên của stash của coderef.

Tất nhiên, điều này được đơn giản hóa và bạn sẽ muốn xem xét lại thông qua @ISA cho các lớp học chung.


Không ai thích không gian tên bị ô nhiễm. Rất may, có các mô-đun xóa ký hiệu nước ngoài khỏi Stash, ví dụ: namespace::clean. Đây là không có vấn đề khi các CV của tất cả các subs bạn đang gọi được biết đến tại thời gian biên dịch.

+3

Sau đó, một lần nữa, đôi khi mọi người thực sự nhập phương thức từ gói khác (ví dụ: 'sử dụng Xuất khẩu 'nhập';' trái với '@ISA = qw (Nhà xuất khẩu);'). – cjm

+0

@cjm Tất nhiên, nhưng tôi đoán điều này không xảy ra thường xuyên, và thậm chí có thể là một hình mẫu. Hy vọng rằng, hầu hết mọi người có tinh thần tách rời lập trình thủ tục (với nhập khẩu) từ OOP (mà giải quyết nhiều vấn đề không gian tên). Không có cách nào để biết nếu một phụ nhập khẩu có nghĩa là một phương pháp, do đó, điều này sẽ phải là đủ tốt. (Đợi đã, có lẽ nếu chúng ta có thể truy cập thuộc tính ': method'…) – amon

+0

_Đây là khá tầm thường_. Không đáng kể? Bạn xây dựng máy phát điện tachyon vào cuối tuần? Perldoc trên ** svref_2object **: _Sẽ tham chiếu đến bất kỳ giá trị Perl nào và chuyển giá trị được gọi vào một đối tượng trong lớp B :: OP có nguồn gốc thích hợp hoặc B :: SV. Tôi không biết nó đang nói về. Tuy nhiên, nó hoạt động. Tôi đoán đã đến lúc tôi phải đi sâu vào những điều chưa được cải thiện trước đó và cải thiện trò chơi Perl của tôi nhiều hơn một chút. Hoặc là, hoặc học Python. –

6

Bạn đang cố gắng làm gì? Tại sao nó lại quan trọng như thế nào một lớp được định nghĩa hoặc thực hiện một phương thức mà nó phản hồi?

Perl là ngôn ngữ động, do đó điều đó có nghĩa là các phương thức không cần phải tồn tại. Với AUTOLOAD, một phương pháp có thể hoàn toàn tốt đẹp và có thể gọi được, nhưng không bao giờ hiển thị trong bảng biểu tượng. Một giao diện tốt sẽ làm cho can hoạt động trong những trường hợp đó, nhưng có thể có trường hợp một lớp hoặc một đối tượng quyết định trả lời điều đó bằng sai.

Mô-đun Package::Stash có thể giúp bạn tìm các trình con được xác định trong một không gian tên cụ thể, nhưng như bạn nói, chúng có thể không được xác định trong cùng một tệp. Các phương thức trong một lớp có thể đến từ một lớp kế thừa. Nếu bạn quan tâm đến nơi họ đến từ, bạn có thể làm điều đó sai.

+0

Tôi có một lớp được gọi là _Sections_ đại diện cho các loại phần khác nhau trong tệp điều khiển của tôi có định dạng Windows INI. Mỗi phần có các tham số, nhưng các tham số khác nhau đối với từng loại Phần. (Hiện tại có năm người trong số họ). Mỗi loại phần là một phân lớp của Phần. Tôi có một lớp khác chứa tất cả danh sách các phần khác nhau cho tôi. Mỗi loại phần được một phương pháp mới trong lớp cuối cùng. Bằng cách này, toàn bộ định nghĩa của tôi cho tệp INI đó nằm trong một đối tượng duy nhất. Một phương thức trong lớp của tôi cho tôi biết tên của tất cả các lớp con khác. –

+0

Tôi đã từng sử dụng AUTOLOAD nhưng bây giờ tôi tránh nó. Sử dụng 'sử dụng strict' làm cho lập trình tốt hơn. Sử dụng cấu trúc tham chiếu sẽ loại bỏ sự an toàn đó. Tôi có thể có '$ foo -> {BAR}' ở một nơi và '$ foo -> {BRA}' ở một nơi khác, và không thể hiểu được '. OO đặt lại sự an toàn đó. Nếu phương thức của tôi là $ foo-> Bar, gọi $ foo-> Bra sẽ làm hỏng chương trình của tôi. AUTOLOAD phá vỡ thiết kế đó. Cả hai đều là phương pháp thực. Nó cũng cho vay với thiết kế tổng thể kém hơn. Tôi có thể cánh nó với AUTOLOAD. Tôi không phải suy nghĩ kỹ. Phiên bản trước của tôi của chương trình này được sử dụng AUTOLOAD, và nó có thể được khó khăn để gỡ lỗi nhờ AUTOLOAD. –

+0

Tôi muốn thêm tất cả giải thích đó vào câu hỏi :) –

Các vấn đề liên quan