mod_perl 2.0 での2種類のハンドラ modperl と perl-script
mod_perl 2.0 では,SetHandler で指定するハンドラタイプとして,modperl と perl-script の2種類があります。この違いは何なんだろうと思い,mod_perl のドキュメント を読み込んでみました。
おおざっぱにまとめると,一般的に使うべきなのは perl-script タイプで,mod_perl のヘルパが便利なようにいろいろ設定してくれてます。たとえば,
- $ENV{QUERY_STRING} や $ENV{REMOTE_ADDR} 等の環境変数を設定してくれている
- STDOUT や STDIN を読み書きすることで,CGI としての入出力ができるようにしてくれている
などですね。
ですから,
- $ENV{REMOTE_ADDR} 等は,$r->connection()->remote_host() 等使って自力で取得するし
- 出力も $r->print() 等使うからいいや
みたく自力でがんばっていてパフォーマンスを重視するハンドラの場合 modperl タイプも選択肢に入ってくると思います(パフォーマンスは気にならないほどの違いだとは思いますが)。また,よりコアに近いモジュールを開発していて perl-script タイプのハンドラで提供されるサービスが余計なお世話だ,と思うときも,modperl タイプが向いていると思います。
結論としては,普通にウェブアプリを開発する場合,perl-script という設定で十分ということです。一応,mod_perl 2.0 のドキュメントの該当部分の意訳を以下に載せておきます。
抄訳
modperl ハンドラタイプ
生の mod_perl ハンドラタイプであり,Perl*Handler コールバック関数を呼ぶことしかしません。perl-script ハンドラの提供する特長が必要ないなら,modperl ハンドラを使うほうがよりよい性能を得ることができます。
(このハンドラは mod_perl 1.0 では使えません)
modperl タイプのハンドラで,ごにょごにょ(*)していない場合,
下記の環境変数しか取得できません。
(*) 「ごにょごにょ」ですが,
設定ファイルにPerlOptions +SetupEnvという設定をしておくか,もしくは,ハンドラの中で,空コンテキストで引数のない
$r->subprocess_env;を呼び出すことにより,その他の環境変数を %ENV に構築することができます。
ですから,単になにがしかの設定値を httpd.conf から取得したい場合,%ENV を構築するオーバーヘッドがいやなら,PerlSetEnv や PerlPassEnv の代わりに PerlSetVar や PerlAddVar を使うことを考慮に入れてみてください。これらの値は dir_config() 関数で取得できます。
たとえば httpd.conf で
<Location /print_env2> SetHandler modperl PerlResponseHandler Apache2::VarTest PerlSetVar VarTest VarTestValue </Location>
と設定してある場合,この値は,Apache2::VarTest::handler() の中で,
$r->dir_config('VarTest');
として取得できます。
この方法の代わりに,Apache コアディレクティブの SetEnv や PassEnv を使うこともできます。これを使うと常に $r->subprocess_env() が呼び出されます。ですが,Apache の fixups フェイズまで呼び出されません。これはタイミングが遅すぎるかもしれませんね。
また,modperl タイプのハンドラは,各リクエストのレスポンスフェイズの後に %ENV をリセットしないことにも注意が必要です。ですから,あるレスポンスハンドラがローカライズすることなく %ENV を変更した場合,他のハンドラにも変更した影響が現れることでしょう。
perl-script ハンドラタイプ
ほとんどの mod_perl ハンドラでは perl-script ハンドラが使われています。特に注目するべき挙動としては,
- 明示的に「PerlOptions -GlobalRequest」としていない限り,PerlResponceHandler フェイズでは PerlOptions +GlobalRequest が有効となっています。
- 明示的に「PerlOptions -SetupEnv」としていない限り,PerlOptions +SetupEnv が有効になっています。
- STDIN と STDOUT がリクエストオブジェクト $r に tie されています。ですから,$r->puts() とか明示的に呼び出さなくても,STDIN からリクエストを読み取ったり,STDOUT に CORE::print() を使ってレスポンスを出力したりできます。
- いくつかの特別な Perl のグローバル変数は,レスポンスハンドラの呼び出しをまたいで保存されます。これは mod_perl 1.0 と同じような挙動です。具体的には,%ENV, @INC, $/, STDOUT の $|, そして END ブロックの配列(PL_endav)です。
- %ENV に追加されたエンティティは,subprocess_env テーブルに複製されます。ですから,PerlLogHandler フェイズや PerlCleanupHandler フェイズで $r->subprocess_env によってそれらを取得可能です。