Защита глобальных переменных во время eval в Test :: Подробнее

Я прокручивал код для Test :: More, потому что я хотел посмотреть, как были реализованы use_ok и require_ok (и почему Ovid им не нравится). Я пришел к _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 без clobbering error vars означает локализацию как $@ и $! , нам также не нужно локализовать $? ?

1 ответ

Мне кажется, что $sigdie существует, чтобы явным образом разрешить код eval'd устанавливать $SIG{__DIE__}, не допуская, чтобы какой-либо обработчик из внешнего управления вступил в силу во время eval.

Таким образом, локализация подавляет внешнее значение, но требует сохранения любого установленного значения до конца блока и установки его в теперь не локализованной версии после блока.

Я предполагаю $! локализован, но не $? , $^E и т.д. По практическим соображениям (т. $^E Я бы предположил, что люди жаловались на изменение $!, но не что-то еще).

licensed under cc by-sa 3.0 with attribution.