首页 > 解决方案 > 如何在我自己的包中重新定义子,但从新包中访问旧包

问题描述

我有一些代码文件开始像

use my_pck;

BEGIN {
    package my_pck;
    my(@p) = ();
    foreach ( keys(%my_pck::) ) {
        push( @p, "\$$_" ) if (defined $$_);
        push( @p, "\%$_" ) if (%$_);
        push( @p, "\@$_" ) if (@$_);
    }
    # ... some extra
    ( @EXPORT = @p, Exporter::import pal ) if ( $#p >= 0 );
}
use strict;
use warnings;

package my_pck;

这部分我不能改变(除了在“一些额外的”处添加一些东西)。

所以现在它里面有一个名为“my_today”的子,因为我需要package my_pck在源文件中使用它在任何地方都可用和经常使用。此方法以“YYYYMMDD”格式给出当前日期。

要检查前一天的一些测试数据,我需要重新定义此方法以提供前一天。

我试图重新定义它

sub my_today {
    my $date = my_pck::my_today();
    $date = my_datefunc($date, "-", 1)  # substracts one day
    return $day;
}

但所以我得到一个错误:

Subroutine my_today redefined at ./my_file.pl line 123.
Deep recursion on subroutine "my_pck::my_today" at ./my_file.pl line 124.
Out of memory!

我该如何解决这个问题?我无法更改整个代码,因为它太多了。

标签: perlpackageperl-exporter

解决方案


你通常想要

{
   my $old_my_today = \&my_pck::mytoday;
   my $new_my_today = sub { my_pck::my_datefunc($old_my_today->(), "-", 1) };
   no warnings qw( redefine );
   *my_pck::mytoday = $new_my_today;
}

问题是新代码必须出现在被替换的 sub 之前,但是我们需要在编译完模块的其余部分之后执行它。为此,我们将使用UNITCHECK.

UNITCHECK块在定义它们的单元被编译之后运行。主程序文件和它加载的每个模块都是编译单元,字符串evals、使用正则表达式中的构造编译的运行时代码、对、(?{ })的调用以及命令行上切换后的代码也是如此。do FILErequire FILE-e

UNITCHECK {
   my $old_my_today = \&my_pck::mytoday;
   my $new_my_today = sub { my_pck::my_datefunc($old_my_today->(), "-", 1) };
   no warnings qw( redefine );
   *my_pck::mytoday = $new_my_today;
}

演示

my_pck.pm

BEGIN {
   UNITCHECK {
      my $old_my_today = \&my_pck::mytoday;
      my $new_my_today = sub { my_pck::my_datefunc($old_my_today->(), "-", 1) };
      no warnings qw( redefine );
      *my_pck::mytoday = $new_my_today;
   }
}

package my_pck;
sub mytoday { 20211011 }
sub my_datefunc { $_[0] - 1 }
1
$ perl -I . -M5.010 -e'use my_pck; say my_pck::mytoday'
20211010

BEGIN绝对没有必要;它只是为了表明UNITCHECK可以在您描述的情况下使用。)


推荐阅读