Защита глобальных переменных во время 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и т. д. по практическим причинам (то есть, я думаю, что люди жаловались на $! меняется, но не более того).

Другие вопросы по тегам