open()の実体
PerlIOが導入されてから,open()の実体はメソッドになっている。Cで実装されたPerlIOレイヤの仮想テーブルからメソッドを探索して,実際のopen()を行うのはそのPerlIOレイヤのopen()メソッドというわけだ。
open my $in, '<:scalar', \my $s;
このように,第二引数でIOレイヤを指定すると,実際にopen()を行うのはPerlIO::scalarのopen()メソッドである。ただし,このメソッドはCレベルで提供されているのでPerlから直接アクセスすることはできない。
IOレイヤを指定しない場合は,デフォルトのIOレイヤが使われる。これはWin32では:unix:crlf,コンパイラのstdioがバッファへ直接アクセスする機能を提供しているときは:stdio,どちらでもない場合は:unix:perlioである(さらに環境変数PERLIOおよびopenプラグマでデフォルトの挙動を変えることもできるが,ここでは詳細は省略)。
レイヤーを複数指定するときは,右が「より上位」と解釈される。
open my $in, '<:unix:perlio', $file;
たとえば上記のコードでは,まず:perlioのopen()が呼び出される。:perlioのopen()は下位のopen()を必要とするので,内部で下位のレイヤである:unix(システムコールを直接行う低レベルIOレイヤ)のopen()を呼び出す。
上記コードの:unixのさらに下位にはデフォルトレイヤが存在するのだが,:unixは下位のopen()を呼び出さないので,そのデフォルトレイヤは無視される。
この挙動は,指定したレイヤにopen()メソッドが存在するケースである。
:utf8(実際にはこれはダミーレイヤなので,メモリ上にレイヤの実体は作られないが)などのレイヤはopen()を持たないので,挙動が異なる。
open my $in, '<:unix:perlio:utf8', $file;
このとき,まず右からopen()を持つレイヤが検索される(この場合は:perlio)。そしてそのレイヤがopen()メソッドを実行し,作成されたPerlIOオブジェクトに対して,先ほどスルーしたopen()を持たないレイヤ(この場合は:utf8)をプッシュする(つまり内部でbinmode $in, ':utf8'相当を行う)。
したがって,open()を持たないレイヤはふつう右側に指定しなければならない。:perlioは直下(すぐ左)のレイヤのopen()を呼び出そうとするので,:utf8が指定されているとそのopen()を呼び出せず,:perlioのopen()を完成できないし,:unixのような低レベルレイヤは直下のレイヤを参照しないので,左側に何を指定されても無視してしまうからだ。したがって以下のような記法は誤りである。
open my $in, '<:utf8:perlio', $file; # *誤り
(PerlIO::Utilの提供するレイヤについてはこれが当てはまらないことがあるが,それはまた別エントリで書く)
まとめ: