Встроенный код, переменные local и my
И еще аналогичный и очень интересный пример:
my $a='1'; $_='2'; print "\$&=$&\n" if $a =~ /^1(?{$_='z'; print "\$_=$_ \$a=$a\n"})$/; print "\$_=$_ \$a=$a";
Будет напечатано
$_=z $a=z $&=z $_=2 $a=z
Из результата мы видим следующее:
- поиск завершился успешно;
- переменная $& должна бы содержать 2, а содержит z ;
- во встроенном коде мы присвоили переменной $_ z, и $a тут же получила это же значение;
- вне оператора поиска переменная $_ сохраняет свое старое значение 2, а $a хранит полученное во встроенном коде значение z.
Можно сделать вывод, что внутри регулярного выражения переменная $_ является синонимом переменной, содержащей целевой текст, как и в операторах map и for (), и переменная $_ локализуется внутри регулярного выражения. Поэтому изменять $_ внутри регулярного выражения так же опасно, как и переменную с целевым текстом.
И еще относительно встроенного кода: встроенный код, который содержится внутри интерполируемых переменных, тоже выполняется, но для этого нужна директива
use re 'eval';
При выполнении скрипта
$_='aaa'; my $a='(?{print "OK "})'; print "$&" if /^aaa$a$/;
Возникнет ошибка
Eval-group not allowed at runtime, use re 'eval' in regex m/^aaa(?{print "OK"})$/ at a.pl line 7.
С директивой use re 'eval' все в порядке:
use re 'eval'; $_='aaa'; my $a='(?{print "OK "})'; print "$&" if /^aaa$a$/;
Заметим, что эта директива не действует внутри встроенного кода:
my $a='(?{use re "eval"; print "OK "})'; print "$&" if /^aaa$a$/;
потому что проверка на встроенный код происходит раньше его использования. Это защищает от использования чужого встроенного кода, например, кода из ввода пользователя.