我希望能够从Perl eval中捕获变量赋值.也就是说,确定在代码中分配了哪些变量名称并提取它们的值.
例如,如果我运行:
eval '$foo=42; $bar=3.14;'
Run Code Online (Sandbox Code Playgroud)
eval的结果是3.14(评估的最后一个值),但我也希望能够确定名称"$ foo"和"$ bar"及其值(事先不知道名称).
我已经阅读了几种通过Safe和Eval :: Context将变量插入eval块的方法,但还没有提取它们的任何方法.我更熟悉Python的eval/exec,它已经内置了对此的支持.
在eval结束后,eval中声明的任何词法变量都将丢失.要捕获和隔离在eval中设置的全局变量,可以考虑使用Safe模块创建新的全局命名空间.类似于以下内容:
use Safe;
my $vars = Safe->new->reval(qq{
$code_to_eval;
$code_to_search_the_symbol_table_for_declared_variables
});
Run Code Online (Sandbox Code Playgroud)
将搜索代码定义为遍历嵌套%main::符号表以搜索任何感兴趣变量的内容.您可以让它返回包含信息的数据结构,然后您可以根据自己的喜好进行操作.
如果您只担心在根级别定义的变量,您可以编写如下内容:
use strict;
use warnings;
my $eval_code = '$foo=42; $bar=3.14;';
use Safe;
my $vars = Safe->new->reval(
$eval_code . q{;
my %vars;
for my $name (keys %main::) {
next if $name =~ /::$/ # exclude packages
or not $name =~ /[a-z]/; # and names without lc letters
my $glob = $main::{$name};
for (qw($SCALAR @ARRAY %HASH)) {
my ($sigil, $type) = /(.)(.+)/;
if (my $ref = *$glob{$type}) {
$vars{$sigil.$name} = /\$/ ? $$ref : $ref
}
}
}
\%vars
});
print "$_: $$vars{$_}\n" for keys %$vars;
# $foo: 42
# $bar: 3.14
Run Code Online (Sandbox Code Playgroud)
搜索代码还可以使用Padwalker使用该peek_my函数搜索任何已定义变量的当前词法范围.
这是我根据 Eric Strom 的建议尝试充实基于Safe 的解决方案。
package main;
use warnings; use strict;
use Safe;
my $cpt = new Safe;
$cpt->permit_only(qw(sassign lineseq padany const rv2sv leaveeval));
my $name_space = $cpt->root;
my $no_strict = 0;
#
# populate the clean symbol table
#
$cpt->reval('0');
die "safe compartment initialisation error: $@" if $@;
my %symtab_clean = do {no strict 'refs'; %{$name_space.'::'} };
my $result = $cpt->reval('$foo=42; $bar=3.14;', $no_strict);
if ($@) {
warn "eval error: $@";
}
else {
#
# symbol table additions
#
my %symtab_dirty = do {no strict 'refs'; %{$name_space.'::'} };
my @updated_variables = grep { ! exists $symtab_clean{$_} } (sort keys %symtab_dirty);
foreach my $variable (@updated_variables) {
my $value = do{ no strict 'refs'; ${$name_space.'::'.$variable} };
print "variable $variable was set to: $value\n"
}
}
Run Code Online (Sandbox Code Playgroud)
笔记: