Perl eval 函数使用
2017-10-05 21:28:19 阿炯

Perl中实现动态代码和异常处理机制的函数:eval

通过eval{}来测试异常,结果在$@中,也可以直接使用die{}来抛出异常。

eval 函数可以看作是 Perl 虚拟机,它的参数就是一段 Perl 代码。利用'perldoc -f eval'可以获取 eval 函数使用帮助,其中介绍了它的两种使用方式:
 
eval EXPR

EXPR 是一个的表达式,例如:
eval "print $a" ;
eval 'print $a' . ', $b' ;
eval 1 + 3 ;
eval 'print ' . '$a + $b, "\n"' ;
eval $command;#$command = ‘print “hello Perl”’
eval $ARGV[0];

在执行时,Perl 解释器会首先解析表达式的值,然后将表达式值作为一条 Perl 语句插入当前执行上下文。所以新生成的语句与 eval 语句本身具有相同的上下文环境。这种方式中,每次执行eval 语句,表达式都会被解析。如果 eval EXPR 如果出现在循环中,表达式可能会被解析多次。 eval 的这种方式使得 Perl 脚本程序能实时生成和执行代码,从而实现了“动态代码”。
 
eval BLOCK

BLOCK 是一个代码块,例如:
eval {print $a};
eval {$a = 1, $b = 2, $c = $a + $b};

与第一种方式不同, BLOCK 只会被解析一次,然后整个插入当前 eval 函数所在的执行上下文。由于解析上的性能的优势,以及可以在编译时进行代码语法检查,这种方式通常被作为 Perl 用来为一段代码提供异常捕捉机制,虽然前一种方式也可以。
 
按帮助的名称,称 eval 的参数程序为“小程序” (mini-program) 。在两种方式中, eval 函数的返回值都是小程序的最后一条语句的值,如果遇到 return 语句,与子例程相同。

eval BLOCK does not count as a loop, so the loop control statements next, last, or redo cannot be used to leave or restart the block.

eval BLOCK不作用于循环,因为循环中的控制语句,next,last,redo不能用于离开或重新启动该块。

my @program;
push ( @program,'my $i = 1;');
push ( @program,'my $i = 3; my $j = 2; my $k = $i + $j');
push ( @program,'my $i = 3; my $j = 0;return 20; my $k = $i + $j');
 
foreach my $exp (@program){
    my $rtn =eval($exp);
    print $rtn,"\n";
}

Output:
1
5
20

In both forms, the value returned is the value of the last expression evaluated inside the mini-program; a return statement may be also used, just as with subroutines. The expression providing the return value is evaluated in void, scalar, or list context, depending on the context of the eval itself. See wantarray for more on how the evaluation context can be determined.

在这两种形式中,返回的值是在小程序内的最后一个表达式的值,还可以使用return语句,就像使用子例程一样。提供返回值的可以是void、标量或列表,这个是由其上下文环境决定的,这取决于eval本身的上下文。有关如何评估上下文的更多信息,请参见wantarray。
 
如果小程序中有语法错误、运行时错误遇到 die 语句,eval 将返回 undef 。错误码被保存在$@中。

push ( @program, '$i = 3; die "error message"; $k = $i + $j');
 
foreach $exp (@program){
    $rtn =eval($exp);
    if (!defined($rtn)){
       print "Exception: " , $@,"\n";
    }
    else{
       print $rtn,"\n";
    }
};

输出:
Exception: error message at (eval 1) line 1.
 
# a run-time error
eval '$answer =' ;# sets $@
warn $@ if $@;

输出:
syntax error at (eval 1) line 2, at EOF


批量连接mysql服务器并执行一查询,如果连接出现问题记录一下问题并跳过此mysql实例。

foreach my $myid (keys %$myst){

eval{$dbh=DBI->connect_cached("DBI:mysql:database=$mdb;host=$myst->{$myid}->{'dbhost'};port=$myst->{$myid}->{'dbport'}",$dbuser,$dbpaswd,\%mydbattr)};
 if($@){
  $mesg.="Mysql host:$myst->{$myid}->{'dbhost'} on Port:$myst->{$myid}->{'dbport'} Has Down?\n";
  next;
 }
 ...
}

参考来源:
eval