Linuxなどのメモ書き

mod_perlハンドラを書く


Rev.2を表示中。最新版はこちら

このテキストは

mod_perl2.0ドキュメントの"Writing mod_perl Handlers and Scripts"(http://perl.apache.org/docs/2.0/user/coding/coding.html)の和訳です。

現在編集中

目次

# Code Developing Nuances

    * Auto-Reloading Modified Modules with Apache2::Reload

# Integration with Apache Issues

    * HTTP Response Headers
          o Generating HTTP Response Headers
          o Forcing HTTP Response Headers Out
    * Sending HTTP Response Body
    * Using Signal Handlers

# Perl Specifics in the mod_perl Environment

    * BEGIN Blocks
    * CHECK and INIT Blocks
    * END Blocks
    * Request-localized Globals
    * exit

# ModPerl::Registry Handlers Family

    * A Look Behind the Scenes
    * Getting the $r Object

# Threads Coding Issues Under mod_perl

    * Thread-environment Issues
    * Deploying Threads
    * Shared Variables

# Maintainers
# Authors

説明

この章ではmod_perlのコーディングの詳細、通常のPerlコーディングとの違いを扱います。その他のほとんどのPerlコーディングに関する情報はperlのmanページや書籍で取り扱われています。

前提

原文なし

Where the Methods Live

mod_perl 2.0では多くのモジュールに跨ってメソッドが存在します。これらのメソッドを使うためにメソッドを含むモジュールは最初にロードしておかないといけません。そうでないと、mod_perlは「メソッドを見つけられない」とエラーにします。どのモジュールが必要かを探すにはModPerl::MethodLookup モジュールが使えます。

Techniques

メソッドハンドラ

関数ハンドラに加えてメソッドハンドラを使うことができます。メソッドハンドラは継承のメリットを生かしたコードを書きたい場合に便利です。mod_perl2のメソッドとしてハンドラを作る場合、method属性を使ってください。

属性の詳細についてはPerlのmanページを参照してください(perldoc attributes)。

例:

  package Bird::Eagle;
  @ISA = qw(Bird);

  sub handler : method {
      my ($class_or_object, $r) = @_;
      ...;
  }

  sub new { bless {}, __PACKAGE__ }

そして、これを以下のようにして登録します。

  PerlResponseHandler Bird::Eagle

mod_perlはハンドラがmethod属性を持っている場合は、2つの引数をハンドラに渡します。上記のコードにもあるようにオブジェクトもしくはクラス名(どのように呼び出されたかに依存します)とRequestオブジェクトです。

以下のようにClass->methodのような形式が使われた場合は、

  PerlResponseHandler Bird::Eagle->handler;

method属性は必要ありません。上の設定例ではhandler()メソッドはクラス(静的)メソッドとして呼び出されます。

メソッドを呼び出すのにオブジェクトを使うこともできます。例えば、

  <Perl>
      use Bird::Eagle;
      $Bird::Global::object = Bird::Eagle->new();
  </Perl>
  ...
  PerlResponseHandler $Bird::Global::object->handler

この例では、hanlder()メソッドはグローバルオブジェクト$Bird::Global::objectのインスタンスメソッドとして呼び出されます。

クリーンアップ

さまざまなフェーズの終わりで発生するクリーンアップ処理をアレンジできます。これを行うのにENDブロックは使えません。なぜなら、ENDブロックはインタプリタが終了するまで実行されないからです(Registryハンドラは例外です)。

モジュール作成者は各HTTPリクエストの後にクリーンアップ処理が必要な場合は、PerlCleanupHandlerを使うべきです。

その他のタイミングでクリーンアップ処理を行う必要がある場合は、プールオブジェクトのcleanup_registerメソッドでクリーンアップコールバックを登録することができます。使用例をいくつか示します。

サーバーのシャットダウンやリスタート時に何か行いたい場合は、startup.plでserver_shutdown_cleanup_register()で登録したクリーンアップハンドラを使ってください。

  #PerlPostConfigRequire startup.pl
  use Apache2::ServerUtil ();
  use APR::Pool ();

  warn "parent pid is $$\n";
  Apache2::ServerUtil::server_shutdown_cleanup_register((\&cleanup);
  sub cleanup { warn "server cleanup in $$\n" }

この方法は、サーバーが停止したり、再起動する時に行うべきサーバー全体のクリーンアップ処理を行うのに便利です。

接続フェーズの終わりにクリーンアップを行う場合は、コネクションプールオブジェクトにクリーンアップコールバックを割り当てます。

  use Apache2::Connection ();
  use APR::Pool ();

  my $pool = $c->pool;
  $pool->cleanup_register(\&my_cleanup);
  sub my_cleanup { ... }

あなた自身のプールオブジェクトを作成してコールバックを登録することもできます。これはオブジェクトが破壊された時に呼び出されます。

  use APR::Pool ();

  {
      my @args = 1..3;
      my $pool = APR::Pool->new;
      $pool->cleanup_register(\&cleanup, \@args);
  }

  sub cleanup {
      my @args = @{ +shift };
      warn "cleanup was called with args: @args";
  }

この例ではクリーンアップコールバックは$poolがスコープの外に出て破壊された時に呼び出されます。これはオブジェクト指向のDESTROYメソッドに非常に似ています。

Goodies Toolkit

環境変数

mod_perlは次の環境変数を設定します。

  • $ENV{MOD_PERL} - mod_perlのバージョンが設定されます

例:

  mod_perl/2.000002

$ENV{MOD_PERL}が存在しなければ、たぶんmod_perl配下で動作していません。

  die "I refuse to work without mod_perl!" unless exists $ENV{MOD_PERL};

どのバージョンが使われているのかチェックするには、次のテクニックを使うとよいです。

  use mod_perl;
  use constant MP2 => ( exists $ENV{MOD_PERL_API_VERSION} and 
                        $ENV{MOD_PERL_API_VERSION} >= 2 ); 

  # die "I want mod_perl 2.0!" unless MP2;

mod_perlは次の環境変数をエクスポートします(それらが設定されていれば)。

  • PATH - 実行可能ファイルのパス
  • TZ - タイムゾーン

これらの環境変数は%ENVでアクセスできます。

スレッド化MPMか否か

実行環境がスレッド化されたMPMかそうでないかでコードが異る動作をする必要があるならApache2::MPM->is_threadedクラスメソッドが使えます。

例:

  use Apache2::MPM ();
  if (Apache2::MPM->is_threaded) {
      require APR::OS;
      my $tid = APR::OS::current_thread_id();
      print "current thread id: $tid (pid: $$)";
  }
  else {
      print "current process id: $$";
  }

このコードはスレッド化されたMPM配下ではカレントスレッドIDを表示します。そうでなければプロセスIDを表示します。

MPM固有のコードを書く

あなたがCPANモジュールを書くなら、全てのMPMで動作しないコードを書くのはまずい考えです。開発者は全てのMPMで動作するコードを書くよう努力すべきです。異るMPM環境で異ることを行うのはまったく立派なことです。

あなたがCPANモジュールを開発しないなら、特定のMPMで動作すればあなたのプロジェクトにとって十分でしょう。

  use Apache2::MPM ();
  my $mpm = lc Apache2::MPM->show;
  if ($mpm eq 'prefork') {
      # prefork-specific code
  }
  elsif ($mpm eq 'worker') {
      # worker-specific code
  }
  elsif ($mpm eq 'winnt') {
      # winnt-specific code
  }
  else {
      # others...
  }

最終更新 2007/05/25 17:51:06 - kztomita
(2007/05/25 17:29:38 作成)


リンク

その他のWiki
Linuxメモ
Xnuメモ

会社
(有)ビットハイブ
受託開発やってます。

よくやる仕事

・Webシステム開発(LAMP環境)
・Linuxサーバー設定関連
サーバー移転作業代行

開発事例にデジタルカタログ/マンガビューワーを追加しました。

draggable.jsのスマホ対応版デモページを追加しました。説明はこちら

検索

Adsense
最近のコメント