Vestavěná funkce Perlu eval je velmi výkonná. V tomto článku se podíváme, jak používat regex v eval, zachytit chyby pomocí eval, vytvořit dynamický kód pomocí eval, vložit kód ze souboru/podprogramu pomocí eval atd.,
Obecná forma perl eval očekává výraz nebo blok kódu jako argument.
1. Rozdíly mezi různými prohlášeními Perl Eval
Podívejme se na následující fragment kódu perl:
$expr =‘$a + $b’;
eval $expr; # 1
eval „$expr“; # 2
eval ‘$expr’; # 3
eval { $expr }; # 4
Případ #1 a #2 jsou identické, kde je perl identifikuje jako platný spustitelný příkaz a vyhodnotí výraz. Výsledek by tedy byl „30“.
V případě #3 nelze výraz rozšířit. Výsledkem je tedy skutečný výraz ($a + $b). To nikdo běžně nepoužívá.
Případ č. 4 je totožný s případem č. 3, ale příkazy uvnitř bloku jsou v době kompilace ověřeny na chyby syntaxe.
2. Práce s regulárními výrazy pomocí Eval
S použitím eval můžeme výrazně snížit počet řádků v kódu, když potřebuje odpovídat řádku pro více než počet regulárních výrazů.
Seznam regulárních výrazů lze vložit do kontejneru (hash / pole) a ve smyčce lze regulární výrazy přebírat jeden po druhém a shodují se se vstupním řádkem, jak je znázorněno níže.
$line = <>; %hash = ( number => qr/^[0-9]+$/, alphabets => qr/^[a-zA-Z]+$/ ); while( my ($key,$value) = each(%hash) ) { if(eval "$line =~ /$value/") { print "$key\n"; } }
3. Perl Eval Error Handling – Trapping Errors
Eval se používá k zachycení chyb. Během provádění podprogramu může program zemřít kvůli chybám nebo externímu volání funkce die. Během této doby, pokud je blok kódu v perlu vykonán uvnitř eval, pak program pokračuje v běhu i po kostce nebo chybách a také zachycuje chyby nebo umísťující slova.
Chyba nulového dělení:
eval { $average = $total / $count }; print “Error captured : $@\n”;
Ve výše uvedeném $count obsahuje hodnotu 0. Když spustíme kód bez bloku eval, program skončí.
Run After Die
sub func { die “dieing in subroutine func\n”; } eval { func(); }; print “Error captured : $@\n”;
Perl eval nemůže zachytit následující chyby:
- Nezachycený signál
- Dochází paměť
- Syntaktické chyby
4. Dynamický kód Perl využívající Eval
Eval umí zkompilovat a spustit kód z řetězce za běhu. Můžeme tedy napsat dynamický program v perlu pomocí eval.
print “Enter number 1 : ”; $data1 = ; print “Enter number 2 : ”; $data2 = ; print “Enter operator : ”; $operator = ; $str = “$data1 $operator $data2”; $result = eval “$data1 $operator $data2”;
Můžeme provést libovolný počet příkazů v eval. Výsledkem eval je poslední vyhodnocený výraz.
Při používání eval na řetězci bychom měli být opatrní, protože může spouštět nedůvěryhodná data z řetězce. Pokud se operace přiřazení musí provádět v samotném řetězci, měli bychom být opatrní při manipulaci s lvalue.
$str = “\$result = $data1 $operator $data2”; eval { $str };
5. Vložení skriptu Perl ze souboru nebo podprogramu během běhu
V perlu můžeme dynamicky načítat moduly za běhu. Abychom moduly načetli dynamicky, musíme použít „vyžadovat“ (ne „použít“).
Ukázkový kód pro načtení modulu, když je vstupní soubor komprimovaný,
$filetype = `file $InputFile`; if($filetype =~ /gzip compressed/) { print "compressed input file...\n"; eval { require PerlIO::gzip; }; }
Běžné podprogramy používané v programech lze rozdělit do souboru, který lze načíst do programů v perlu pomocí eval, jak je uvedeno níže.
File : common_routines.pl sub open_file { .... } sub read_file { .... } sub write_file { .... } sub close_file { .... } In the perl script, sub load_file_subroutines { open CODE, 'common_routines.pl'; undef $\; my $code = <code>; close CODE; eval $code; die $@ if $@; }</code>
6. Perl Eval v Input Time-outs
Funkce knihovny standardních alarmů se používá ke generování signálu SIGALRM po určité době. To by nám hlavně pomohlo vyhnout se blokování čekání na uživatelský vstup. To lze použít s eval k získání uživatelského vstupu ve stanoveném čase, jak je znázorněno v příkladu níže.
$SIG{ALRM} = \&input_timed_out; eval { alarm (10); $buf = <>; alarm(0); # Cancel the pending alarm if user responds. }; if ($@ =~ /NO USER INPUT IN TIME/) { print "Timed out.\n"; } sub input_timed_out { die "NO USER INPUT IN TIME"; }