【Perl】”サブクラスをインスタンス化するメソッド”を動的に追加する方法を考える

投稿日: / 更新日:

この記事は2年以上前に書かれたものです。情報が古い可能性があります。

CatalystDBIx::Classなどのように、

こんな感じで、あらかじめサブクラスをuseしなくとも、必要になった時に動的にサブクラスをuseして欲しい場合があります。

2012/11/26 12:55追記:そもそも、このような事をしたい背景として、サブクラスを後で追加した場合に大元のクラスに変更を加えたくない、ということが挙げられます。

お手軽に実現しようと思った場合、UNIVERSAL::requireを使用する方法があります。サンプルコード等は以下のとおりです(ついでに、クラスのインスタンス取得にsingletonパターンを使用しています)。

実行例のとおり、存在するサブクラスについてはインスタンスが取得でき、存在しないサブクラスについては例外が投げられました。これは期待どおりの動作です。

では、上記より一歩進めて、サブクラスをインスタンス化するメソッドの名前を”サブクラス名(をアンダースコア記法に直したもの)”にしたい場合、どのようにすれば良いでしょうか。実行したいイメージは以下のとおりです。

存在するサブクラスのモジュールファイルを全てリストアップして、それぞれのクラスをインスタンス化するためのメソッドを動的に作成する、という方法も考えられますが、もう少し手っ取り早く実現しようとした場合、AUTOLOADを使う方法が考えられます。早速、My::Class.pmを改造してみます。

ここで特筆すべきは、(該当するサブルーチンがないために)AUTOLOADが呼び出された後、それ以後同じサブルーチンについて再度AUTOLOADが呼び出されないで済むよう、サブルーチン名をパッケージのシンボルテーブルに登録している点です。ここでは、クロージャをグロブに割り当てることで、それを実現しています。また、サブルーチン名をシンボルテーブルに登録した後は、そのサブルーチンを&付きのgoto文で呼び出します。これによりサブルーチン呼び出しのカレントスタックフレームが取り除かれ、呼び出し元は直接その(新しく登録された)サブルーチンを呼び出したのと同じことになります。なお、この辺りのテクニックは、「実用Perlプログラミング」(O’Reilly)に詳しく説明されています。

それでは、テストスクリプトにテスト項目を追加して、再度動作確認してみます。

 

期待どおり動作することが確認できました。

なお、上記のAUTOLOADを使用した方法のcaveatとして、サブクラス名(のそれぞれの単語)は先頭が大文字で、2文字目以降は全て小文字である必要があります(サブルーチン名からサブクラス名への変換ロジックを見れば一目瞭然ではありますが…)。これにうまく対処したバージョンの作成は、次回の課題にしたいと思います。

以上、Perlに関するトピックをご紹介しました。

Hinemos導入はアトミテックにお任せください

見積もりを依頼する

最新情報発信中

Xやメルマガでも、Hinemosの保守、
開発、導入、構築やカスタマイズ等の
お役立ち情報を発信しています。
是非ご登録ください。