你可以在Perl中拦截方法调用,对参数做些什么,然后执行它?是否可以拦截Perl方法调用?
回答
是的,你可以拦截Perl子程序调用。我在Mastering Perl中有关于这类事情的整章。查看Hook::LexWrap模块,该模块可让您在不通过所有细节的情况下执行此操作。 Perl的方法只是子例程。
你也可以创建一个子类并覆盖你想要捕获的方法。这是一个稍微好一些的方法,因为这就是面向对象编程希望你做到的方式。但是,有时候人们会编写不允许您正确执行此操作的代码。 Mastering Perl还有更多关于这方面的内容。
这看起来像Moose的工作! Moose是Perl的一个对象系统,可以做到更多。 docs在解释方面会做得比我更好,但您可能需要的是Method Modifier,特别是before
。
麋是你用于整个应用程序的东西,而不是有针对性的问题。 – 2009-09-01 22:08:50
但这取决于问题是什么,问题的提问者没有说明任何细节。这可能是某人评估创建新应用程序时要采取的方法,在这种情况下,开启Moose将是一个合适且有益的响应。 – jsoverson 2009-09-01 23:03:28
我们只是说了同样的事情。我没有说不使用穆斯,但我也没有说要使用它。 – 2009-09-02 00:53:09
简而言之,Perl具有修改符号表的能力。您可以通过程序包所属的包的符号表调用子程序(方法)。如果您修改符号表(并且这不是很脏),则可以用调用您指定的其他方法替换大多数方法调用。这证明了方法:
# 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);
这也表明,一旦有人需要子程序的引用,并通过引用调用它,你再也不能影响这样的电话。
我很确定有框架在perl中进行方位化,但是我希望这个方法能够证明这种方法。
是的。
您需要三样东西:
的参数来调用在@_
这只是另一种动态范围的变量。
然后,goto
支持reference-sub参数,该参数保留当前的@_
但是进行另一个(尾部)函数调用。
最后local
可用于创建词汇范围的全局变量,符号表被埋在%::
。
所以,你有:
sub foo {
my($x,$y)=(@_);
print "$x/$y = " . ((0.0+$x)/$y)."\n";
}
sub doit {
foo(3,4);
}
doit();
这当然打印出:
3/4 = 0.75
我们可以通过local
foo换成去:
my $oldfoo = \&foo;
local *foo = sub { (@_)=($_[1], $_[0]); goto $oldfoo; };
doit();
而现在我们得到:
4/3 = 1.33333333333333
如果你想修改*foo
不使用它的名字,而你不想通过操纵%::
使用eval
,那么你可以修改它,例如:
$::{"foo"} = sub { (@_)=($_[0], 1); goto $oldfoo; };
doit();
而现在我们得到:
3/1 = 3
你可以和帕维尔描述了一个好办法做到这一点,但你应该详细说明,为什么你想要做这个摆在首位。
如果您正在寻找拦截对任意子例程的调用的高级方法,那么摆弄符号表将适合您,但是如果您想为可能导出到您当前使用的命名空间的函数添加功能,那么您可能需要知道如何调用其他名称空间中存在的函数。
例如,Data :: Dumper通常会将函数'Dumper'导出到调用名称空间,但您可以覆盖或禁用该函数并提供您自己的Dumper函数,然后通过完全限定名称调用原始函数。
例如
use Data::Dumper;
sub Dumper {
warn 'Dumping variables';
print Data::Dumper::Dumper(@_);
}
my $foo = {
bar => 'barval',
};
Dumper($foo);
再次,这是一个替代的解决方案取决于原始问题,即可能更合适。使用符号表时可以带来很多乐趣,但如果你不需要它可能会导致难以维护的代码。
在这种情况下,你应该给Dumper一个空的进口清单,所以你不要输入任何东西。另外,在这种情况下序列很重要。您必须先导入,然后覆盖。最后的子程序定义获胜。最后,在警告下,你会得到一个“重新定义”的错误。 – 2009-09-02 00:55:38
当然,只是为了举例而保持简单。直接对直接有更多的价值(对响应者来说更快)比解释每个切线细节。无论如何,导入和警告的概念将被最好地解释为其他问题。 – jsoverson 2009-09-02 01:15:33
- 1. 是否可以拦截Documentum API调用?
- 2. 是否可以使用unity 3.0拦截私有方法?
- 3. .NET方法调用拦截
- 4. Python拦截方法调用
- 5. 是否可以拦截READ操作?
- 6. Caliburn Micro - 是否可以拦截调用来执行命令?
- 7. 可以拦截私人方法吗?
- 8. 不使用拦截器绑定调用拦截器方法
- 9. 拦截Perl中不存在的方法调用
- 10. 拦截器方法未被调用
- 11. 拦截方法调用Objective-C
- 12. 拦截调用定义的PHP方法
- 13. 如何拦截实例方法调用?
- 14. Python中的拦截方法调用
- 15. 跟踪/拦截方法调用
- 16. 拦截PHP中的方法调用
- 17. 统一拦截调用基本方法
- 18. 如何“拦截”测试方法调用?
- 19. 如何拦截dll方法调用?
- 20. C#4拦截方法调用
- 21. 拦截每个http调用ES6方法
- 22. 通用方法拦截
- 23. 如何拦截类方法调用,而不仅仅是实例方法调用
- 24. 是否可以使用动态代理拦截构造函数调用?
- 25. 是否可以使用Fetch API作为请求拦截器?
- 26. 是否可以拦截Android应用程序中的电话?
- 27. 是否可以使用ES2016代理拦截“typeof”操作?
- 28. 是否可以使用注释来连接Spring MVC拦截器?
- 29. 是否可以拦截directx 11调用并将它们转换为directx 12?
- 30. 在调用GetControllerInstance之前是否可以拦截ProcessRequest来确定表单超时?
我看到你使用了标签“aop”。为什么不问你想使用的具体AOP技术? (你的问题的答案可能会帮助你实现一个AOP系统,但为什么当别人已经做到了?) – jrockway 2009-09-01 23:19:45
我认为这可以用方法属性完成,但现在我找不到合适的perldoc页面(perldoc属性不是我想到的页面)。我记得一个很好的例子,涉及包装添加日志中的各种方法... – Ether 2009-09-02 00:39:50
请参阅此相关的SO问题的其他信息:http://stackoverflow.com/questions/635212/how-i-redefine-perl-class-methods – draegtun 2009-09-06 15:08:31