上周,我被意外覆盖了子类中的方法而被咬了两次。虽然我不是继承的粉丝,但我们(ab)在我们的应用程序中使用它。我想要做的是提供一些声明性语法来声明方法覆盖父方法。像这样:
use Attribute::Override;
use parent 'Some::Class';
sub foo : override { ... } # fails if it doesn't override
sub bar { ... } # fails if it does override
这里有几个问题。首先,如果方法加载以某种方式延迟(例如,通过AUTOLOAD加载的方法或稍后安装在符号表中的方法),则不会检测这些方法。
走继承树也可能同样昂贵。我使用Class::Sniff执行此操作,但它不适合运行代码。我可以遍历继承树并简单匹配适当的符号表中定义的CODE插槽的位置,并且速度会更快,但如果方法缓存失效,那么如果我要缓存这些结果,那将会中断。
所以我有两个问题:这是一个合理的方法,是否有一个钩子,允许我检查方法缓存是否已更改? (在'perldoc perlobj'中搜索'cache')。
当然,这不应该破坏生产代码,我只考虑让它失败或警告TEST_HARNESS环境变量是否处于活动状态(并且有一个显式的环境变量来强制它处于非活动状态,如果生产代码是由于某种原因设置TEST_HARNESS环境变量。)
答案 0 :(得分:6)
强制执行此操作的一种方法:
package Base;
...
sub new {
my $class = shift;
...
check_overrides( $class );
...
}
sub check_overrides {
my $class = shift;
for my $method ( @unoverridable ) {
die "horribly" if __PACKAGE__->can( $method ) != $class->can( $method );
}
}
check_overrides的记忆可能会有所帮助。
如果在某些情况下您需要豁免,请使用备用方法名称 让基类调用:
package Base;
...
my @unoverridable = 'DESTROY';
sub destroy {}
sub DESTROY {
my $self = shift;
# do essential stuff
...
$self->destroy();
}