Phasers: BEGIN, UNITCHECK, CHECK, INIT, END#
Five specially named blocks let code hook the transitions a program makes between being compiled and being run. They look like subroutines but are not: you can write several of each, none has a callable name, and each one fires automatically at its own moment.
BEGIN { ... } # during compilation, as soon as defined
UNITCHECK { ... } # right after this compilation unit is compiled
CHECK { ... } # after the whole program is compiled
INIT { ... } # just before the runtime begins
END { ... } # just before the interpreter exits
The sub prefix (sub BEGIN { ... }) is accepted but adds nothing and is discouraged. These are blocks, not named subs; you cannot call them, only let them fire.
When each one runs#
A Perl program lives in two phases: a compile phase that parses the source into an internal form, and a run phase that executes it. The phasers mark the boundary.
BEGINruns the instant its closing brace is parsed, before the rest of the file is even read. This is howuseworks: auseis aBEGIN-wrappedrequireplusimport, so the imported names exist for the code that follows. Once aBEGINhas run, it is undefined and its memory reclaimed.UNITCHECKruns as soon as the compilation unit that contains it has finished compiling. A unit is the main program, a module loaded byrequire, a stringeval, adoFILE, or code compiled by the(?{ })regex construct. Because units finish compiling at different times,UNITCHECKis the only phaser whose timing tracks the individual file rather than the program as a whole.CHECKruns once, after the initial compile phase of the whole program ends and before the run phase starts.INITruns once, just before the run phase begins, after allCHECKblocks.ENDruns once, as late as possible: after the program has finished (including after adie), just before the interpreter exits.
BEGIN and UNITCHECK are tied to parsing, not to the interpreter phase, so they can fire during any phase: a string eval at run time still compiles its body, and any BEGIN or UNITCHECK inside it runs then and there. CHECK and INIT, by contrast, mark the one-time compile/run boundary of the main program.
Multiplicity and execution order#
You may write any number of each block. They all run, in a defined order:
BEGIN: first in, first out (FIFO) as encountered during compilation. The firstBEGINin source order runs first.UNITCHECK: last in, first out (LIFO) within each unit, after that unit compiles.CHECK: LIFO, after all compilation.INIT: FIFO, just before the runtime.END: LIFO at exit. The lastENDdefined is the first to run.
The instructive case is a file that mixes ordinary statements with all five block kinds. The blocks do not run where they are written; they run at their phase, in their per-phase order, while the ordinary statements run in between at run time. Conceptually, for a single file:
1. BEGIN blocks -- FIFO, during compilation
2. UNITCHECK blocks -- LIFO, after this unit compiles
3. CHECK blocks -- LIFO, after all compilation
4. INIT blocks -- FIFO, just before runtime
5. ordinary code -- run phase, in source order
6. END blocks -- LIFO, at exit
So BEGIN and UNITCHECK run before any CHECK; CHECK runs before INIT; INIT runs before the first line of ordinary code; and every END runs after the last. Within BEGIN and INIT, earlier-written blocks run earlier; within UNITCHECK, CHECK, and END, later-written blocks run earlier.
END blocks in detail#
END is the cleanup phaser. It runs LIFO so that teardown unwinds in the reverse of setup, the way nested resources expect.
Inside an END block, $? holds the value the program is about to pass to exit. You may read it to learn how the program is ending, and you may assign to it to change the exit code:
END {
$? = 0 if $? == 42; # rewrite one exit code on the way out
}
Beware of clobbering $? by accident. Running anything via system inside an END block overwrites $? with the child’s status, which then becomes the program’s exit code unless you save and restore it.
END blocks do not run in several cases:
Under the
-cswitch (compile-only syntax check). Main code does not run, and neither doENDblocks.When compilation fails. A program that does not compile never reaches the point where
ENDblocks would fire.When the process replaces itself with
exec. The image is gone; there is nothing left to run the block.When the process is killed by a fatal signal you do not trap. Catch the signal yourself (via
%SIG) if you need cleanup to run.
An END block created inside a string eval is not run when that eval finishes. It is registered like any other END block of its package and runs in LIFO order just before the interpreter exits.
${^GLOBAL_PHASE} and the phases#
The read-only variable ${^GLOBAL_PHASE} names the interpreter’s current phase. Its values let code that runs in more than one phase find out where it is. During a CHECK block it reads CHECK; during INIT, INIT; during ordinary run-time code, RUN; during an END block, END. See ${^GLOBAL_PHASE} for the full list of values and the phase timeline.
defer blocks#
A defer block is END’s small-scale cousin. It runs when the enclosing block scope exits, for any reason, rather than when the whole program exits. Reach for defer to pair acquisition with release inside a sub or loop; reach for END for process-wide teardown that must happen once, at the very end.
See also#
BEGINanduse-useis aBEGIN-wrapped load-and-import; the most common reason to care about compile-phase timing.${^GLOBAL_PHASE}- read the current phase from inside any block to learn where you are.defer- block-scoped cleanup, the right tool whenEND’s program-wide reach is too broad.$?- the exit status anENDblock can read and rewrite.%SIG- trap the signals that would otherwise bypassENDblocks entirely.exit- whatENDblocks run just before; the value it carries is the$?anENDblock sees.