Können Sie einen Methodenaufruf in Perl abfangen, etwas mit den Argumenten tun und dann ausführen?Können Perl-Methodenaufrufe abgefangen werden?
Antwort
Ja, Sie können Perl-Unterprogrammaufrufe abfangen. Ich habe ein ganzes Kapitel über diese Art von Dingen in Mastering Perl. Schauen Sie sich das Modul Hook::LexWrap an, mit dem Sie das tun können, ohne alle Details durchgehen zu müssen. Perls Methoden sind nur Subroutinen.
Sie können auch eine Unterklasse erstellen und die Methode überschreiben, die Sie abfangen möchten. Das ist ein etwas besserer Weg, weil das objektorientierte Programmieren so machen will. Manchmal schreiben jedoch Leute Code, der es Ihnen nicht erlaubt, dies richtig zu machen. Es gibt mehr darüber in Mastering Perl auch.
Das sieht nach einem Job für Moose aus! Moose ist ein Objektsystem für Perl, das das und noch viel mehr kann. Die docs wird viel besser erklären, als ich kann, aber was Sie wahrscheinlich wollen, ist ein Method Modifier, speziell before
.
Elch ist etwas, das Sie für die gesamte Anwendung verwenden, nicht gezielte Probleme. –
Aber es hängt davon ab, was das Problem ist, und der Fragesteller der Frage gibt keine Details an. Es könnte jemand sein, der einen Ansatz auswertet, den man bei der Erstellung einer neuen Anwendung anstellen sollte, und in diesem Fall wäre es eine angemessene und nützliche Antwort, wenn man sich an Moose wendet. – jsoverson
Wir sagten nur das Gleiche. Ich habe nicht gesagt, ich solle Elch nicht gebrauchen, aber ich habe auch nicht gesagt, es zu benutzen. –
Um kurz zu beschreiben, Perl hat die Fähigkeit, Symboltabelle zu ändern. Sie rufen ein Unterprogramm (Methode) über die Symboltabelle des Pakets auf, zu dem die Methode gehört. Wenn Sie die Symboltabelle ändern (und dies wird nicht als sehr schmutzig betrachtet), können Sie die meisten Methodenaufrufe durch Aufrufen der anderen von Ihnen angegebenen Methoden ersetzen. Dies zeigt die Vorgehensweise:
# The subroutine we'll interrupt calls to
sub call_me
{
print shift,"\n";
}
# Intercepting factory
sub aspectate
{
my $callee = shift;
my $value = shift;
return sub { $callee->($value + shift); };
}
my $aspectated_call_me = aspectate \&call_me, 100;
# Rewrite symbol table of main package (lasts to the end of the block).
# Replace "main" with the name of the package (class) you're intercepting
local *main::call_me = $aspectated_call_me;
# Voila! Prints 105!
call_me(5);
Dies zeigt auch, dass, wenn schon jemand anhand des Unterprogramms nimmt und ruft sie über den Bezug, können Sie nicht mehr solche Anrufe beeinflussen.
Ich bin mir ziemlich sicher, dass es Frameworks gibt, die Aspiration in Perl durchführen, aber das, hoffe ich, zeigt den Ansatz.
Ja.
Sie brauchen drei Dinge:
Die Argumente für ein Gespräch in @_
, die nur ein weiteres dynamisch scoped Variable ist.
Dann unterstützt goto
ein Reference-Sub-Argument, das die aktuelle @_
erhält, aber einen anderen (Tail-) Funktionsaufruf macht.
Schließlich kann local
verwendet werden, um lexikalisch begrenzte globale Variablen zu erstellen, und die Symboltabellen sind in %::
eingebettet.
So haben Sie bekam:
sub foo {
my($x,$y)=(@_);
print "$x/$y = " . ((0.0+$x)/$y)."\n";
}
sub doit {
foo(3,4);
}
doit();
die natürlich druckt:
3/4 = 0.75
Wir foo local
verwenden ersetzen können und gehen:
my $oldfoo = \&foo;
local *foo = sub { (@_)=($_[1], $_[0]); goto $oldfoo; };
doit();
Und jetzt bekommen wir :
4/3 = 1.33333333333333
Wenn Sie wollen *foo
ändern, ohne seinen Namen zu verwenden, und Sie wollten nicht eval
verwenden, dann könnte man es ändern, indem %::
, zum Beispiel der Manipulation:
$::{"foo"} = sub { (@_)=($_[0], 1); goto $oldfoo; };
doit();
Und wir bekommen jetzt:
3/1 = 3
Sie können, und Pavel beschreibt eine gute Möglichkeit, es zu tun, aber Sie sollten wahrscheinlich erarbeiten, warum Sie dies in erster Linie tun möchten.
Wenn Sie nach erweiterten Möglichkeiten suchen, Aufrufe an beliebige Subroutinen abzufangen, dann funktioniert das Hantieren mit Symboltabellen für Sie, aber wenn Sie Funktionalität zu Funktionen hinzufügen möchten, die vielleicht in den Namensraum exportiert werden, in dem Sie gerade arbeiten, Dann müssen Sie möglicherweise wissen, wie Sie Funktionen aufrufen können, die in anderen Namespaces vorhanden sind.
Zum Beispiel exportiert Data :: Dumper normalerweise die Funktion 'Dumper' in den aufrufenden Namespace, aber Sie können diese überschreiben oder deaktivieren und eine eigene Dumper-Funktion bereitstellen, die dann das Original über den vollständig qualifizierten Namen aufruft.
z.B.
Wieder ist dies eine alternative Lösung, die je nach dem ursprünglichen Problem besser geeignet sein kann. Es kann viel Spaß gemacht werden, wenn man mit der Symboltabelle spielt, aber es kann übertrieben sein und dazu führen, dass Code schwer zu pflegen ist, wenn man ihn nicht braucht.
In diesem Fall sollten Sie eine leere Importliste zu Dumper geben, damit Sie nichts importieren. In diesem Fall spielt auch die Reihenfolge eine Rolle. Sie müssen zuerst importieren und dann überschreiben. Die letzte Unterprogrammdefinition gewinnt. Schließlich erhalten Sie unter Warnungen einen "Neudefinieren" -Fehler. –
Auf jeden Fall nur versuchen, es einfach zu halten, um ein Beispiel zu nennen. Direkt zu sein hat mehr Wert (und ist für den Antwortenden schneller) als jedes tangentiale Detail zu erklären. Die Konzepte des Imports und der Warnungen würden am ehesten als andere Fragen erklärt. – jsoverson
- 1. Wie können Systemaufrufe unter Unix-Umgebungen abgefangen werden?
- 2. Wie alle Berührungsereignisse abgefangen werden?
- 3. System.Printing.PrintQueueException kann nicht abgefangen werden
- 4. ConstraintViolationException kann nicht abgefangen werden
- 5. QDockWidget - Schriften werden abgefangen (Unterlänge)
- 6. Ausnahmen werden im GCC-Programm nicht abgefangen
- 7. Kann eine NSInternalInconsistencyException in Swift abgefangen werden?
- 8. Chrome-Erweiterung: Wie abgefragte URLs abgefangen werden?
- 9. Ausnahmen werden nicht von 'try' abgefangen
- 10. Wie können Ausnahmen abgefangen und auf die Fehlerseite in Lift umgeleitet werden?
- 11. Warum können Haskell-Ausnahmen nur innerhalb der IO-Monade abgefangen werden?
- 12. Wie werden alle Ausnahmen abgefangen, die in der Symfony2-Controlleraktion auftreten können?
- 13. Wie können Ausnahmen in den Aktionen des Controllers richtig abgefangen werden?
- 14. System.Reflection.TargetInvocationException wird nicht abgefangen
- 15. Java-Ausnahme nicht abgefangen
- 16. ArrayOutofBound Ausnahme nicht abgefangen
- 17. Swing Mouse Listeners von Kind Komponenten abgefangen werden
- 18. Wie alle Ausnahmen in der Flasche abgefangen werden?
- 19. DataIntegrityViolationException konnte nicht mit Spring Data abgefangen werden REST
- 20. Warum AccessViolationException von .NET4.0 nicht abgefangen werden kann
- 21. Laufzeitausnahmen werden mit ACRA abgefangen und nicht in Logcat angezeigt
- 22. Kann der Fehler "Zugriff in einem inkonsistenten Zustand" abgefangen werden?
- 23. Ausnahmen ignorieren, die in einer Bibliothek ausgelöst und abgefangen werden
- 24. Wie kann eine bestimmte Ausnahme in JDBC abgefangen werden?
- 25. SQLiteConstraintException nicht abgefangen
- 26. Java-Ausnahme nicht abgefangen?
- 27. Ausnahme nicht abgefangen
- 28. Wiederholungsausnahme wird nicht abgefangen
- 29. Zugriffsverletzung in WM_PAINT nicht abgefangen
- 30. EJB TransactionRolledBackException ist nicht abgefangen
Ich sehe, dass Sie den Tag "AOP" verwendet. Fragen Sie nach bestimmten AOP-Techniken, die Sie verwenden möchten. (Die Antworten auf Ihre Frage können Ihnen helfen, ein AOP-System zu implementieren, aber warum, wenn jemand anderes es bereits getan hat?) – jrockway
Ich dachte, dies könnte mit Methodenattributen gemacht werden, aber jetzt kann ich die entsprechende perldoc-Seite nicht finden ist nicht die Seite, an die ich gedacht habe). Ich erinnere mich an ein schönes Beispiel mit verschiedenen Methoden zum Hinzufügen in Protokollierung ... – Ether
Siehe diese Frage SO für weitere Informationen: http://StackOverflow.com/Questions/635212/how-i-redefine-perl-Class-Methods – draegtun