gpt4 book ai didi

perl - (如何)我可以在调用 Symbol::delete_package 之后重新创建一个包吗?

转载 作者:行者123 更新时间:2023-12-02 06:50:15 26 4
gpt4 key购买 nike

给定一个小型 Perl 库:

package P;

use strict;
use warnings;

print("Loading P\n");

our $k1 = 'v1';
our $k2 = 'v2';
our $k3 = 'v2';

我尝试编写一个加载、卸载和重新加载包的程序,以便更好地理解包在 Perl 中的工作方式:

# main.pl
use strict;
use warnings;
use Symbol qw( delete_package );

# Load module
require "./P.pm";
my @incs = sort keys %INC;
my $numSyms = keys %P::;
print("Includes: @incs\nNumber of symbols: $numSyms\n");

# Unload module & delete package
delete_package('P');
delete $INC{'./P.pm'};
@incs = sort keys %INC;
$numSyms = keys %P::;
print("Includes: @incs\nNumber of symbols: $numSyms\n");

# Load module again
require "./P.pm";
@incs = sort keys %INC;
$numSyms = keys %P::;
print("Includes: @incs\nNumber of symbols: $numSyms\n");

运行这个程序会打印一些类似的东西(模块被 keys %INC 列出的顺序可能不同):

Loading P
Includes: ./P.pm Exporter.pm Symbol.pm strict.pm warnings.pm
Number of symbols: 4
Includes: Exporter.pm Symbol.pm strict.pm warnings.pm
Number of symbols: 0
Loading P
Includes: ./P.pm Exporter.pm Symbol.pm strict.pm warnings.pm
Number of symbols: 0

即重新加载库似乎按预期工作,但符号表 %P:: 仍然是空的。为什么第二次加载库时没有重新填充它?我正在尝试找到一种无需使用任何 CPAN 包即可重新加载模块的方法。

最佳答案

问题是 %P:: 在编译时解析,所以它指的是 glob delete_package 被清除并导致符号表被拒绝。

如果通过替换强制查找在运行时发生,您将获得预期的输出

keys %P::;

keys %{ no strict qw( refs ); \%{"P::"} };

keys %{ $::{"P::"} };

这意味着仅仅卸载一个包是不够的;您需要卸载对包进行硬编码引用的代码以及从包中导入的代码!

删除包的程序(例如快速 CGI 守护程序中的脚本加载器)通常不会硬编码对它们删除的包的引用,因此它们通常不会遇到此问题。下面是一个例子:

use strict;
use warnings;
use Symbol qw( delete_package );

use FindBin qw( $RealBin );
use lib $RealBin;

sub mod_path {
my ($mod_name) = @_;
return ( $mod_name =~ s{::}{/}gr ) . ".pm";
}

sub load_module {
my ($mod_name) = @_;
my $mod_path = mod_path($mod_name);
require $mod_path;
}

sub unload_module {
my ($mod_name) = @_;
my $mod_path = mod_path($mod_name);
delete_package($mod_name);
delete($INC{$mod_path});
}

sub get_package {
my ($pkg_name) = @_;
$pkg_name .= '::' if $pkg_name !~ /::\z/;
my $pkg = \%::;
$pkg = $pkg->{$_} for split /(?<=::)/, $pkg_name;
return $pkg;
}

sub dump_info {
my ($mod_name) = @_;
my $mod_path = mod_path($mod_name);
my $pkg = get_package($mod_name);

my $is_in_inc = grep { $_ eq $mod_path } keys %INC;
printf("Included: %s\n", $is_in_inc ? "yes" : "no");

my $num_syms = keys(%$pkg);
print("Number of symbols: $num_syms\n");

print("\n");
}

for $mod_name ('P', 'P') {
load_module($mod_name); dump_info($mod_name);
# $mod_name->run();
unload_module($mod_name); dump_info($mod_name);
}

关于perl - (如何)我可以在调用 Symbol::delete_package 之后重新创建一个包吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46852200/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com