前段时间,我问过这个关于覆盖构建perl函数的问题.
如何以允许多个覆盖的方式执行此操作?以下代码产生无限递归.
这样做的正确方法是什么?如果我重新定义一个函数,我不想踩到别人的重新定义.
package first;
my $orig_system1;
sub mysystem {
my @args = @_;
print("in first mysystem\n");
return &{$orig_system1}(@args);
}
BEGIN {
if (defined(my $orig = \&CORE::GLOBAL::system)) {
$orig_system1 = $orig;
*CORE::GLOBAL::system = \&first::mysystem;
printf("first defined\n");
} else {
printf("no orig for first\n");
}
}
package main;
system("echo hello world");
Run Code Online (Sandbox Code Playgroud)
Sch*_*ern 20
正确的方法是不要这样做.找到一些其他方法来完成你正在做的事情.这种技术具有全局变量的所有问题,平方.除非你完全正确地重写函数,否则你可能会破坏你从未知道的各种代码.虽然你可能会礼貌地不吹嘘现有的覆盖,但其他人可能不会.
覆盖system
特别敏感,因为它没有合适的原型.这是因为它做了原型系统中无法表达的事情.这意味着你的覆盖不能做一些事情system
.即...
system {$program} @args;
Run Code Online (Sandbox Code Playgroud)
这是一种有效的调用方式system
,但您需要阅读exec
文档才能执行此操作.你可能会想"哦,我当时就不会那么做",但是如果你使用的任何模块,或者它使用的任何模块都做到了,那么你就不走运了.
也就是说,礼貌地覆盖任何其他功能几乎没有什么不同.您必须捕获现有功能,并确保在新功能中调用它.无论您是在之前还是之后完成,都取决于您.
您的代码中的问题是检查函数是否已定义的正确方法是defined &function
.使用代码引用,即使是未定义的函数,也将始终返回真正的代码引用.我不知道为什么,也许它\undef
会如何返回标量参考.为什么调用这个代码ref导致mysystem()
无限递归是任何人的猜测.
还有一个额外的复杂性,你不能参考核心功能. \&CORE::system
不是你的意思.你也不能用象征性的参考来得到它.因此,如果要CORE::system
根据定义的内容调用或现有覆盖,则不能仅将一个或另一个分配给代码引用.你必须分裂你的逻辑.
这是一种方法.
package first;
use strict;
use warnings;
sub override_system {
my $after = shift;
my $code;
if( defined &CORE::GLOBAL::system ) {
my $original = \&CORE::GLOBAL::system;
$code = sub {
my $exit = $original->(@_);
return $after->($exit, @_);
};
}
else {
$code = sub {
my $exit = CORE::system(@_);
return $after->($exit, @_);
};
}
no warnings 'redefine';
*CORE::GLOBAL::system = $code;
}
sub mysystem {
my($exit, @args) = @_;
print("in first mysystem, got $exit and @args\n");
}
BEGIN { override_system(\&mysystem) }
package main;
system("echo hello world");
Run Code Online (Sandbox Code Playgroud)
请注意,我已经将mysystem()更改为仅仅是在真实系统之后运行的钩子.它获取所有参数和退出代码,它可以更改退出代码,但它不会改变system()
实际操作.如果要保留现有覆盖,则可以在挂钩之前/之后添加唯一的操作.无论如何它还是有点安全.最重要的系统现在是一个子程序,以防止BEGIN过于混乱.
您应该能够根据需要修改它.
归档时间: |
|
查看次数: |
3427 次 |
最近记录: |