Защита глобальных переменных во время eval в Test::More
Я просматривал код для Test::More, потому что хотел посмотреть, как use_ok
а также require_ok
были реализованы (и почему Овидий не любит их). Я пришел к _eval
подпрограмма, которая содержит некоторую специальную логику, которую я не совсем понимаю для защиты переменных во время eval
вызов. Из документации Try::Tiny я понимаю, насколько сложно иметь дело с $@
, Тем не менее, я не понимаю, как обращаться с $!
а также $SIG{__DIE__}
(ниже блок скопирован дословно):
# Work around oddities surrounding resetting of $@ by immediately
# storing it.
my( $sigdie, $eval_result, $eval_error );
{
local( $@, $!, $SIG{__DIE__} ); # isolate eval
$eval_result = eval $code; ## no critic (BuiltinFunctions::ProhibitStringyEval)
$eval_error = $@;
$sigdie = $SIG{__DIE__} || undef;
}
# make sure that $code got a chance to set $SIG{__DIE__}
$SIG{__DIE__} = $sigdie if defined $sigdie;
Обработка $SIG{__DIE__}
относится к RT # 34065, но я до сих пор не понимаю. Почему необходимо снова установить переменную в этой последней строке, поскольку она всегда должна устанавливаться в последней строке блока? Если весь смысл этих строк состоит в том, чтобы установить переменную, какой она стала в eval
позвоните, почему он должен быть локализован в первую очередь?
Также при использовании eval
без забитой ошибки переменная означает локализацию обоих $@
а также $!
мы не должны также локализовать $?
?
1 ответ
Это выглядит как $sigdie
есть, чтобы явно позволить eval'd код для установки $SIG{__DIE__}
, не позволяя никакому внешне установленному обработчику вступать в силу во время eval.
Таким образом, локализация подавляет внешнее значение, но требует сохранения любого заданного значения до конца блока и установки его в теперь не локализованной версии после блока.
Я предполагаю $!
локализован но не $?
, $^E
и т. д. по практическим причинам (то есть, я думаю, что люди жаловались на $!
меняется, но не более того).