Perl方法调用可以被拦截吗?
你能在 Perl 中拦截一个方法调用,对参数做一些事情,然后执行它吗?
Can you intercept a method call in Perl, do something with the arguments, and then execute it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,您可以拦截 Perl 子例程调用。我在 Mastering Perl 中有一整章关于此类事情。查看 Hook::LexWrap 模块,它可以让您无需完成所有操作即可完成此操作的细节。 Perl 的方法只是子例程。
您还可以创建一个子类并重写您想要捕获的方法。这是一个稍微好一点的方法,因为这是面向对象编程希望您这样做的方式。然而,有时人们编写的代码不允许您正确执行此操作。 掌握 Perl 中也有更多相关内容。
Yes, you can intercept Perl subroutine calls. I have an entire chapter about that sort of thing in Mastering Perl. Check out the Hook::LexWrap module, which lets you do it without going through all of the details. Perl's methods are just subroutines.
You can also create a subclass and override the method you want to catch. That's a slightly better way to do it because that's the way object-oriented programming wants you do to it. However, sometimes people write code that doesn't allow you to do this properly. There's more about that in Mastering Perl too.
简单地说,Perl 具有修改符号表的能力。您可以通过方法所属包的符号表来调用子例程(方法)。如果修改符号表(这并不被认为是非常脏的),则可以用调用您指定的其他方法来替换大多数方法调用。这演示了该方法:
这也表明,一旦有人引用子例程并通过引用调用它,您就无法再影响此类调用。
我非常确定有框架可以在 perl 中进行方面分析,但我希望这可以演示该方法。
To describe briefly, Perl has the aptitude to modify symbol table. You call a subroutine (method) via symbol table of the package, to which the method belongs. If you modify the symbol table (and this is not considered very dirty), you can substitute most method calls with calling the other methods you specify. This demonstrates the approach:
This also shows that, once someone takes reference of the subroutine and calls it via the reference, you can no longer influence such calls.
I am pretty sure there are frameworks to do aspectation in perl, but this, I hope, demonstrates the approach.
这看起来像是 Moose 的工作! Moose 是 Perl 的一个对象系统,可以做到这一点以及更多。 文档 在解释方面会比我做得更好,但是什么您可能需要一个 方法修饰符,特别是
之前
。This looks like a job for Moose! Moose is an object system for Perl that can do that and lots more. The docs will do a much better job at explaining than I can, but what you'll likely want is a Method Modifier, specifically
before
.您可以,并且帕维尔描述了一种很好的方法,但您可能应该首先详细说明为什么要这样做。
如果您正在寻找拦截对任意子例程的调用的高级方法,那么摆弄符号表将适合您,但如果您想向可能导出到您当前正在使用的命名空间的函数添加功能,那么您可能需要了解调用其他名称空间中存在的函数的方法。
例如,Data::Dumper 通常将函数“Dumper”导出到调用命名空间,但您可以覆盖或禁用该函数并提供您自己的 Dumper 函数,该函数然后通过完全限定名称调用原始函数。
例如
,这又是一个替代解决方案,根据原始问题,它可能更合适。使用符号表可以带来很多乐趣,但它可能有点过头了,并且如果您不需要它,可能会导致代码难以维护。
You can, and Pavel describes a good way to do it, but you should probably elaborate as to why you are wanting to do this in the first place.
If you're looking for advanced ways of intercepting calls to arbitrary subroutines, then fiddling with symbol tables will work for you, but if you want to be adding functionality to functions perhaps exported to the namespace you are currently working in, then you might need to know of ways to call functions that exist in other namespaces.
Data::Dumper, for example, normally exports the function 'Dumper' to the calling namespace, but you can override or disable that and provide your own Dumper function which then calls the original by way of the fully qualified name.
e.g.
Again, this is an alternate solution that may be more appropriate depending on the original problem. A lot of fun can be had when playing with the symbol table, but it may be overkill and could lead to hard to maintain code if you don't need it.
是的。
您需要三件事:
调用的参数位于
@_
中,这只是另一个动态作用域变量。然后,
goto
支持引用子参数,该参数保留当前的@_
但进行另一个(尾部)函数调用。最后,
local
可用于创建词法作用域的全局变量,并且符号表隐藏在%::
中。所以你已经得到了:
当然会打印出:
我们可以使用
local
替换 foo 并执行:现在我们得到:
如果你想修改
*foo
而不使用它的name,并且你不想使用eval
,那么你可以通过操作%::
来修改它,例如:现在我们得到:
Yes.
You need three things:
The arguments to a call are in
@_
which is just another dynamically scoped variable.Then,
goto
supports a reference-sub argument which preserves the current@_
but makes another (tail) function call.Finally
local
can be used to create lexically scoped global variables, and the symbol tables are buried in%::
.So you've got:
which of course prints out:
We can replace foo using
local
and go:And now we get:
If you wanted to modify
*foo
without using its name, and you didn't want to useeval
, then you could modify it by manipulating%::
, for example:And now we get: