How does open 0; print <0>; turn every Perl program into a quine?

The other day, on the heels of a brief exchange of tweets:

Make a Perl program print itself:

seek(DATA,0,0);
print while (<DATA>);
__DATA__

#perltrick

— PerlTricks (@PerlTricks) September 19, 2014

@PerlTricks @PerlSawyer shorter version:

open 0;
print while <0>;

— Rafaël Garcia-Suarez (@consttype) September 19, 2014

@consttype @PerlTricks @PerlSawyer if *short* (as in golfing) is a measurement here,

open 0;print for<0>;

— Tux (H.Merijn Brand) (@Tux5) September 19, 2014

I chirped in to point out that neither the while nor the for is necessary as the arguments to print print are evaluated in list context, therefore automatically slurping the contents of the bareword filehandle 0, and printing them:

@Tux5 @consttype @PerlTricks @PerlSawyer Actually, if you are golfing,

open 0;
print <0>;

will do.

— A. Sinan Unur (@sinan_unur) October 2, 2014

But, why is open 0; equivalent to opening the source of the script that is running?

You probably do know that the special variable $0 holds the name of the program that is being executed. It is not universally guaranteed (see perldoc -v '$0'), but this will usually be a string you can pass to open to open the source of your script.

But, how does open 0 end up opening this file?

To my dismay, I found that perldoc -f open in most recent versions of Perl don’t have this, but versions as recent as 5.18.2 explain what happens when open is invoked with a single argument:

If EXPR is omitted, the global (package) scalar variable of the same name as the FILEHANDLE contains the filename.

Clearly, I don’t recommend relying on this: If nothing else, you should avoid using global variables, and you should use the three argument form of open anyway. I am just explaining how this trick works.

So, when perl sees open 0;, it does the equivalent of open 0, '<', $0.

You can easily verify this:

$ cat 0.pl
#!/usr/bin/env perl

# We are not golfing any more
use autodie;
use strict;
use warnings;

$0 = 'does not exist'; # Thanks Peter
open 0;

$ ./0.pl
Can't open('0'): No such file or directory at ./0.pl line 9

Another example:

$ cat evil.pl
#!/usr/bin/env perl

'does not exist.txt' =~ /\A(.+)\z/;

open 1;
print <1>;

$ cat 'does not exist.txt'
it
 does
  exist
   -- Dr. Evil

$ ./evil.pl
it
 does
  exist
   -- Dr. Evil

Ouch!