One possible reason for why while(<>) does not implicitly localize $_ as part of its magic is that sometimes you want to access the last value of $_ outside the loop. For example:
while (<>) {
chomp;
last if /\S/;
}
print "You said: $_\n";
If $_ were localized, you would have to copy the value to another variable:
my $in;
while (local $_ = <>) {
chomp;
$in = $_, last if /\S/;
}
print "You said: $in\n";
Although it may just be as Abigail said, that foreach always assigns to a variable as part of the loop, whereas while can have anything in the conditional and (<>) is just a special case.