Czy możesz przechwycić wywołanie metody w Perlu, zrób coś z argumentami, a następnie wykonaj je?Czy wywołania metody Perl mogą zostać przechwycone?
Odpowiedz
Tak, można przechwytywać wywołania podprogramów Perl. Mam cały rozdział na ten temat w Mastering Perl. Sprawdź moduł Hook::LexWrap, który pozwala to zrobić bez przechodzenia przez wszystkie szczegóły. Metody Perla to tylko podprogramy.
Można także utworzyć podklasę i zastąpić metodę, którą chcesz przechwycić. Jest to nieco lepszy sposób, ponieważ jest to sposób, w jaki programowanie obiektowe chce, abyś to robił. Czasami jednak ludzie piszą kod, który nie pozwala ci zrobić tego poprawnie. Więcej na ten temat również w Mastering Perl.
To wygląda na pracę dla Moose! Łoś to system obiektowy dla Perla, który może to zrobić i wiele więcej. docs wykona o wiele lepszą pracę przy wyjaśnianiu niż ja, ale prawdopodobnie będziesz potrzebował Method Modifier, konkretnie before
.
Łoś jest czymś, co używasz do całej aplikacji, a nie ukierunkowanymi problemami. –
Ale to zależy od problemu, a osoba pytająca nie poda żadnych szczegółów. Może to być ktoś, kto oceni podejście, które przyjmie podczas tworzenia nowego wniosku, w którym to przypadku włączanie do łosia byłoby odpowiednią i korzystną reakcją. – jsoverson
Po prostu powiedzieliśmy to samo. Nie powiedziałem, że nie używam Łosia, ale nie powiedziałem, żeby go użyć. –
Aby krótko opisać, Perl ma możliwość modyfikowania tabeli symboli. Wywołujesz podprogram (metodę) poprzez tablicę symboli pakietu, do którego należy ta metoda. Jeśli zmodyfikujesz tabelę symboli (i nie jest to uważane za bardzo brudne), możesz zastąpić większość wywołań metod, wywołując inne określone metody. Świadczy to podejście:
# 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);
ten pokazuje również, że gdy ktoś bierze odniesienie podprogramu i wzywa go poprzez odniesienie, nie można już wpływać na takie połączenia.
Jestem prawie pewien, że istnieją ramy do zrobienia aspektu w perlu, ale mam nadzieję, że to podejście demonstruje.
Tak.
potrzebne są trzy rzeczy:
argumentów do rozmowy są w @_
który jest po prostu kolejną zmienną dynamicznie scoped.
Następnie goto
obsługuje argument podrzędny odniesienia, który zachowuje bieżący @_
, ale wykonuje inne wywołanie funkcji (ogon).
Na koniec można użyć local
do utworzenia globalnych zmiennych o zasięgu leksykalnym, a tabele symboli są pochowane w %::
.
Więc masz:
co oczywiściesub foo {
my($x,$y)=(@_);
print "$x/$y = " . ((0.0+$x)/$y)."\n";
}
sub doit {
foo(3,4);
}
doit();
drukuje:
3/4 = 0.75
Możemy zastąpić foo przy użyciu local
i idź:
my $oldfoo = \&foo;
local *foo = sub { (@_)=($_[1], $_[0]); goto $oldfoo; };
doit();
A teraz mamy :
4/3 = 1.33333333333333
Jeśli chcesz zmodyfikować *foo
bez używania jego nazwy, a ty nie chcesz używać eval
, to można go modyfikować poprzez manipulowanie %::
, na przykład:
$::{"foo"} = sub { (@_)=($_[0], 1); goto $oldfoo; };
doit();
A teraz mamy:
3/1 = 3
Możesz, a Pavel opisuje dobry sposób na zrobienie tego, ale powinieneś prawdopodobnie wyjaśnić, dlaczego chcesz to zrobić w pierwszej kolejności.
Jeśli szukasz zaawansowanych sposobów przechwytywania wywołań do dowolnych podprogramów, to będzie Ci pomocny manipulator z tabelami symboli, ale jeśli chcesz dodać funkcjonalność do funkcji, być może wyeksportowanych do przestrzeni nazw, w której aktualnie pracujesz, wtedy być może trzeba będzie znać sposoby wywoływania funkcji istniejących w innych obszarach nazw.
Dane :: Dumper, na przykład, normalnie eksportuje funkcję "Dumper" do wywołującej przestrzeni nazw, ale można ją przesłonić lub wyłączyć i dostarczyć własną funkcję Dumper, która następnie wywołuje oryginał za pomocą w pełni kwalifikowanej nazwy.
np.
use Data::Dumper;
sub Dumper {
warn 'Dumping variables';
print Data::Dumper::Dumper(@_);
}
my $foo = {
bar => 'barval',
};
Dumper($foo);
To alternatywne rozwiązanie, które może być bardziej odpowiednie w zależności od pierwotnego problemu. Dużo radości można uzyskać podczas gry przy użyciu tablicy symboli, ale może to być przesada i może prowadzić do trudnego do utrzymania kodu, jeśli go nie potrzebujesz.
W tym przypadku powinieneś podać pustą listę importu do Dumper, więc nie importujesz niczego. Również w tym przypadku kolejność ma znaczenie. Najpierw należy zaimportować, a następnie przesłonić. Wygrywa ostatnia definicja podprogramu. Na koniec, w ramach ostrzeżeń, otrzymasz komunikat "przedefiniuj". –
Zdecydowanie, po prostu staram się zachować prostotę ze względu na przykład. Bycie bezpośrednim ma większą wartość (i jest szybsze dla respondenta) niż wyjaśnienie wszystkich szczegółów stycznych. Koncepcje importu i ostrzeżeń można najlepiej wyjaśnić jako pozostałe pytania. – jsoverson
- 1. Czy metody kategorii mogą zostać nadpisane? IOS
- 2. Poczekaj wewnątrz metody, aż zostanie przechwycone zdarzenie
- 3. Jak obsłużyć zarówno przechwycone i nieprzechwycone błędy w podprogramie Perl?
- 4. Eclipse wizualizacji łańcucha wywołania metody
- 5. Czy biblioteki DLL Rcpp mogą zostać rozładowane bez restartowania R?
- 6. Perl gwintowania metody obiektu
- 7. Czy funkcje obiektu wywołania funkcji mapy Pythona mogą być używane?
- 8. Czy istnieje sposób wywołania metody, gdy ustawiona jest właściwość klasy?
- 9. Android - Zdjęcie przechwycone
- 10. Kiedy należy użyć & do wywołania podprogramu Perl?
- 11. Jak przechwycić wywołania metody instancji?
- 12. Subskrybowanie metody PropertyChanged lub metody wywołania metody setter?
- 13. Czy metody asynchroniczne mogą kosztować kod przed pierwszym "oczekiwaniem"?
- 14. Czy metody rozszerzania C# mogą uzyskać dostęp do zmiennych prywatnych?
- 15. Czy metody Cashusa strehibuf C++ mogą generować wyjątki?
- 16. Klucze obce w postgresql mogą zostać naruszone przez wyzwalacz
- 17. Czy czas wywołania metody super klasy jest ważny w ObjectiveC?
- 18. Czy wywołania metody Javascript są wątkowane lub synchronizowane?
- 19. Fałszywe nieużywane metody "prywatne" powinny zostać usunięte.
- 20. Jakie typy bibliotek standardowych OCaml nie mogą zostać ustawione?
- 21. TypeError: Dane obrazu nie mogą zostać przekształcone w zmienną wartość
- 22. Uzyskiwanie identyfikatora wątku bieżącego wywołania metody
- 23. Metody serwisowe nie mogą zwrócić pustki. retrofit
- 24. Wywołania metody analizy porównawczej w języku C#
- 25. Przypisywanie i zwiększanie wartości podczas wywołania metody
- 26. Jaśmin - śledzenie wywołania metody w konstruktorze
- 27. Zamknięcie nie zostało przechwycone? - Coffeescript
- 28. niemożliwe zachowanie wywołania metody języka Java
- 29. Dlaczego ReSharper mówi mi "niejawnie przechwycone zamknięcie"?
- 30. nazwa wywołania metody zawartej w łańcuchu znaków
Widzę, że użyłeś tagu "aop". Dlaczego nie zapytać o konkretne techniki AOP, z których chciałbyś skorzystać? (Odpowiedzi na twoje pytanie mogą pomóc w implementacji systemu AOP, ale dlaczego tak się dzieje, gdy ktoś już to zrobił?) – jrockway
Myślałem, że można to zrobić za pomocą atrybutów metod, ale teraz nie mogę znaleźć odpowiedniej strony perldoc (atrybuty perldoc nie jest stroną, o której myślałem). Pamiętam dobry przykład dotyczący zawijania różnych metod dodawania rejestrowania ... – Ether
Zobacz powiązane pytanie SO, aby uzyskać dodatkowe informacje: http://stackoverflow.com/questions/635212/how-i-redefine-perl-class-methods – draegtun