2009-06-20 22 views

Antwort

13

Die Empfehlung, die Todd Gardner gab, um Elch zu verwenden, ist eine gute, aber der von ihm gewählte Beispielcode ist nicht sehr hilfreich.

Wenn Sie einen nicht-Elch mit Klasse Inspektion, würden Sie so etwas tun:

use Some::Class; 
use Class::MOP; 

my $meta = Class::MOP::Class->initialize('Some::Class'); 

for my $meth ($meta->get_all_methods) { 
    print $meth->fully_qualified_name, "\n"; 
} 

Siehe Class::MOP::Class docs für weitere Details, wie Selbstbeobachtung zu tun.

Sie werden auch feststellen, dass ich Class :: MOP anstelle von Moose verwendet habe. Class :: MOP (MOP = Meta-Object Protocol) ist die Basis, auf der Moose baut. Wenn du mit Nicht-Moose-Klassen arbeitest, bringt dir die Verwendung von Moose zur Introspektion nichts.

Wenn Sie wollten, könnten Sie use Moose() und Moose::Meta::Class->initialize anstelle von CMOP.

+0

+1: Das ist ordentlich, ich wusste nicht, dass Sie Class :: MOP so verwenden könnten. –

+1

Ich erkläre die Grenzen dieser in meiner Antwort. Selbst mit einer leeren Klasse kann es die Methoden von UNIVERSAL nicht aufnehmen und kann keine von AUTOLOAD aufnehmen. –

+0

@brian d foy: Verwenden von AUTOLOAD ist schlecht, mmmkay? – HoldOffHunger

3

Hängt davon ab, wenn Sie meinen, irgendeine Klasse, oder wenn Sie Ihre eigenen implementieren würden. Für letzteres verwende ich Moose, was eine sehr saubere Syntax für diese Funktionen bietet. Aus dem Kochbuch:

my %attributes = %{ $self->meta->get_attribute_map }; 
for my $name (sort keys %attributes) { 
    my $attribute = $attributes{$name}; 

    if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled') 
    # ... keeps on 
+0

Beachten Sie, dass Moose keine Attribute findet, es sei denn, die Klasse, die Sie inspizieren, wurde zuerst mit Moose definiert. Die Methodenintrospektion, wie auch die meisten anderen Bits, funktioniert jedoch gut. –

5

Im allgemeinen Fall, werden Sie die Symboltabelle überprüfen müssen (es sei denn, Sie Moose verwenden). Um zum Beispiel die Verfahren, die in dem Paket definierten IO::File aufzulisten:

use IO::File; 
no strict 'refs'; 
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::}; 

Der Hash %{IO::File::} ist die Symboltabelle der IO::File package und die grep filtert nicht-Subroutine Einträge (z.B. Paketvariablen).

Um dies auf vererbte Methoden zu erweitern, müssen Sie rekursiv die Symboltabellen der übergeordneten Klassen (@IO::File::ISA) durchsuchen.

Hier ist ein komplettes Beispiel:

sub list_methods_for_class { 
    my $class = shift; 
    eval "require $class"; 
    no strict 'refs'; 
    my @methods = grep { defined &{$class . "::$_"} } keys %{$class . "::"}; 
    push @methods, list_methods_for_class($_) foreach @{$class . "::ISA"}; 
    return @methods; 
} 

Für weitere Informationen über Pakete und Symboltabellen finden Sie in der perlmod -Handbuchseite.

+0

Nicht jede Methode muss in der Symboltabelle definiert sein, und Sie vermissen UNIVERSAL. –

+0

Ich habe mich gefragt, ob irgendwelche Lösungen für diese Frage, besonders hier eine, eine neue Objektinstanz erzeugen, wenn der Code aufgerufen wird und wenn er wiederverwendet wird oder jede Instanz im Speicher verbleibt, bis das Programm beendet wird. Da Reflektion/Introspektion in einigen anderen Sprachen wie .NET und Java verwendet werden muss, muss sorgfältig darauf geachtet werden, wo die Klassenobjekt-Referenz instanziiert wird. Andernfalls können neue Instanzen pro Aufruf abgerufen werden. – David

3

Wahrscheinlich möchten Sie die Klasse :: Inspector-> Methoden ('Ihre :: Klasse').

Nuff sagte.

10

Sie können leicht eine Liste der definierten Methoden einer Klasse mit den bereits bereitgestellten Antworten erhalten. Perl ist jedoch eine dynamische Sprache, was bedeutet, dass später weitere Methoden definiert werden können. Es gibt wirklich keine Möglichkeit, eine Liste aller Methoden zu erhalten, mit denen eine bestimmte Klasse umgehen kann. Für viel mehr Details über diese Art von Sachen, habe ich ein paar Kapitel in Mastering Perl.

Die Leute geben Ihnen (und Upvoting) Antworten, ohne Ihnen von den Einschränkungen zu erzählen.

Adam erwähnt seine Class::Inspector, aber es funktioniert nicht wirklich, weil es versucht, etwas zu tun, was eine dynamische Sprache nicht tut (und das ist statisch :) Zum Beispiel ist hier ein Ausschnitt, in dem Class :: Inspector keine Methoden zurückgibt , aber ich kann immer noch die VERSION Methode (sowie isa und can) nennen:

BEGIN { 

package Foo; 

our $VERSION = '1.23' 
} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # reports nothing 

print Foo->VERSION, "\n"; 

Hier ist ein weiterer Fall, in dem ich eine Methode aufrufen kann ich mag, aber Klasse :: Inspektor gibt nur AUTOLOAD (und fehlt noch VERSION , isa und can):

BEGIN { 

package Foo; 

our $VERSION = '1.23'; 

my $object = bless {}, __PACKAGE__; 

sub AUTOLOAD { $object } 

} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # reports only "AUTOLOAD" 

print Foo->dog->cat->bird, "\n"; 

Seltsamerweise scheint jeder UNIVERSAL zu ignorieren, wahrscheinlich weil sie nicht explizit damit umgehen, da es nur virtuell in @ISA ist. Ich kann eine debug Methode zu jeder Klasse hinzufügen und Class :: Inspektor noch fehlt es, obwohl es eine definierte Methode ist:

BEGIN { 

sub UNIVERSAL::debug { "Hello debugger!\n" }  
package Foo; 
} 

use Class::Inspector; 

my $methods = Class::Inspector->methods('Foo'); 

print "Methods are [@$methods]\n"; # still reports nothing 

print Foo->debug, "\n"; 

Class::MOP hat die gleichen Einschränkungen.

Nicht jedes Modul wird AUTOLOAD verwenden, aber es ist auch keine obskure oder seltene Funktion. Wenn es Ihnen nichts ausmacht, dass Sie einige der Methoden vermissen, dann könnte Class :: Inspector oder Class :: MOP in Ordnung sein. Es wird Ihnen nicht nur eine Liste aller Methoden geben, die Sie für eine Klasse oder ein Objekt in jedem Fall aufrufen können.

Wenn Sie eine Klasse oder ein Objekt haben und wissen möchten, ob Sie eine bestimmte Methode aufrufen können, verwenden Sie can(). Wickeln Sie es in einem eval-Block so kann() aufrufen können auf Dinge, die nicht einmal Objekte sind immer noch zurück falsch zu bekommen, statt des Todes, in diesen Fällen:

if(eval { $object->can('method_name') }) 
    { 
    $object->(@args); 
    } 
0

Ich werde nur diese lassen sich hier für wenn ich es vergesse. Das ist extrem mächtig; Schade, dass es so aus dem Weg ist, dass die meisten Perl-Programmierer es nie erfahren.

package Foo; 
use strict; 
sub foo1 {}; 
sub foo2 {}; 
our $foo3 = sub{}; 
my $foo4 = "hello, world!"; 

package Bar; 
use strict; 

# woo, we're javascript! 
(sub { 
    *Bar::foo1 = sub { print "hi!"; }; 
    *Bar::foo2 = sub { print "hello!"; }; 
    $Bar::foo1 = 200; 
})->(); 

package main; 
use strict; 
use Data::Dumper;  
$Data::Dumper::Deparse = 1; 

print Dumper \%Data::Dumper::; 
print Dumper \%Foo::; 
print Dumper \%Bar::; 
Verwandte Themen