В Perl существуют специальные блоки (BEGIN, CHECK, INIT, END), которые позволяют управлять временем выполнения кода:
BEGIN { ... } — выполняется сразу при компиляции файла (до основного кода и до загрузки модулей);CHECK { ... } — исполняется после компиляции всех файлов, но до их выполнения (не во всех версиях Perl поддерживается);INIT { ... } — выполняется до начала выполнения основного кода ("runtime");END { ... } — выполняется после завершения программы, при выходе из скрипта.Порядок исполнения:
BEGINCHECKINITENDПример:
BEGIN { print "BEGIN executed "; } CHECK { print "CHECK executed "; } INIT { print "INIT executed "; } print "Main code executed "; END { print "END executed "; }
Может ли блок BEGIN внутри модуля повлиять на глобальное состояние программы, если этот модуль подключен с помощью require, а не use?
Ответ и пример:
Блоки BEGIN исполняются при компиляции, поэтому они не выполнятся, если модуль подключён через require (во время выполнения, не при компиляции), а не через use (исполняется во время компиляции включающего файла). Это может привести к неожиданному поведению, если инициализация положена на BEGIN.
История 1: В одном проекте использовался
BEGINдля инициализации переменных окружения, а модуль подключался черезrequire— в результате переменные не были установлены, что внесло хаос в загрузку конфигураций на продакшене.
История 2: При использовании блока
ENDдля закрытия файлового дескриптора не учитывались неявные остановки процесса; иногдаEND-блок не срабатывал из-за аварийного завершения работы Perl-интерпретатора, что приводило к потерянным данным в логах.
История 3: Блоки
CHECKбыли единственным местом запуска тестов на валидность окружения. Пользователь запускал скрипт в старой версии Perl, где не было блокаCHECK, и проверки просто не проводились — критические сбои проявлялись только в продуктиве.