如何解决无法修改的 Perl 库中的“die”调用?
-
19-08-2019 - |
题
是的,问题出在我正在使用的库上,不,我无法修改它。我需要一个解决方法。
基本上,我正在处理一个写得不好的 Perl 库,当读取文件时遇到特定错误情况时,该库会以“die”退出。我从一个程序中调用这个例程,该程序循环访问数千个文件,其中一些文件是错误的。坏文件时有发生;我只想让我的例程记录一个错误并继续。
如果我可以修改库,我只需更改
die "error";
到一个
print "error";return;
, , 但是我不能。有什么方法可以调整例程,以便坏文件不会使整个过程崩溃?
后续问题:使用“eval”来处理容易崩溃的调用效果很好,但是如何在该框架内设置对可捕获错误的处理?来描述:
我有一个子例程,有时会多次调用该库,该库有时会崩溃。我没有使用 eval{} 来处理此子例程中的每个调用,而是让它终止,并在调用我的子例程的级别上使用 eval{}:
my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails
但是,我可以并且确实在 function() 中捕获了一些错误条件。在子例程和调用例程中设计错误捕获的最正确/优雅的方法是什么,以便我对捕获和未捕获的错误都获得正确的行为?
解决方案
您可以在一个eval
包裹。参见:
perldoc -f eval
例如,你可以写:
# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;
这会变成致命错误变成警告,这或多或少是你的建议。如果die
被调用,$@
包含传递给它的字符串。
其他提示
是否有陷阱 $SIG{__DIE__}
?如果是的话,那么它比你更本地化。但有几个策略:
您可以调用它的包并 覆盖 死:
package Library::Dumb::Dyer; use subs 'die'; sub die { my ( $package, $file, $line ) = caller(); unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) { say "It's a good death."; die @_; } }
如果没有的话可以 陷阱 它。(在页面上查找 $SIG,markdown 不处理完整链接。)
my $old_die_handler = $SIG{__DIE__}; sub _death_handler { my ( $package, $file, $line ) = caller(); unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) { say "It's a good death."; goto &$old_die_handler; } } $SIG{__DIE__} = \&_death_handler;
您可能需要扫描图书馆,找到它的子目录 总是 调用,并用它来加载你的
$SIG
通过覆盖处理程序that
.my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb; *Dumb::do_something_dumb = sub { $SIG{__DIE__} = ... goto &$dumb_package_do_something_dumb; };
或者重写它的内置函数 总是 打电话...
package Dumb; use subs 'chdir'; sub chdir { $SIG{__DIE__} = ... CORE::chdir @_; };
如果其他方法都失败了,你可以用以下方法鞭打马的眼睛:
package CORE::GLOBAL; use subs 'die'; sub die { ... CORE::die @_; }
这将覆盖 死 在全球范围内,这是您返回的唯一途径 die
是将其解决为 CORE::die
.
将其组合起来会起作用。
虽然改变die
不管芯具有如在其他的答案中所示的特定的解决方案,一般可以总是覆盖其他包中的子程序。你完全不改变原来的来源。
首先,让你获得所有的原始定义的装入原包装。一旦原始就位,就可以重新定义麻烦子程序:
BEGIN {
use Original::Lib;
no warnings 'redefine';
sub Original::Lib::some_sub { ... }
}
您甚至可以剪切和粘贴的原始定义和调整你所需要的。这不是一个很好的解决方案,但如果你不能改变原始来源(或希望更改原始之前尝试的东西),它可以工作。
除此之外,您可以将原始源文件复制到你的应用程序一个单独的目录。因为您可以控制目录,你可以在它编辑的文件。您修改副本,并通过添加目录到Perl的模块搜索路径加载:
use lib qw(/that/new/directory);
use Original::Lib; # should find the one in /that/new/directory
您复制棍棒甚至周围是否有人更新原始模块(尽管你可能需要合并更改)。
我说说这个颇有几分在掌握的Perl ,在这里我展示一些其他技术做之类的东西。诀窍是更不打破东西。你怎么不打破东西取决于你在做什么。