~~NOTOC~~ ---json { "title":"_load()", "description":"モジュール(パッケージ)に定義されているローダルーチン(load())を呼び出します" } --- \\ ====== _load() ======
==== 説明 ==== モジュール(パッケージ)に定義されているローダルーチン(load())を呼び出します。\\ ==== 構文 ====~~DISCUSSION~~_load()==== 引数 ==== ありません。\\ ==== 返り値 ==== ありません。\\ ==== 備考 ==== この関数は、関数start()から呼び出されるので、単独で呼び出す必要はありません。\\ ローダルーチンは、大規模なアプリケーション処理をモジュール(パッケージ)ごとに分割したときに、 各モジュールの初期処理やイベント処理を定義するような場合に使用します。\\ 分割したモジュールに\\package Module; sub load { : }と定義しておき、関数start()を呼び出すとサーバが開始される直前で定義したローダルーチンが呼び出されます。\\ ロードした全てのモジュール(パッケージ)ファイルにローダルーチンが含まれているものは全て呼び出されますが、package Module; our $NOLOAD=1;としておくと、ローダルーチンの呼び出しを抑止することができます。\\BBS.pmでは関数名を load とするとローダルーチンとして識別しますので、目的の用途以外として定義する場合は別の関数名を使用してください。\\ あるモジュールのローダルーチンの結果を他のモジュールで参照するような処理を行うと、誤動作を起こす場合があります。\\ これは、各モジュールのローダルーチンの呼び出し順序が決まっていないことが原因です。\\ 例えば、AとA-DASHの2つモジュールがあるとします。\\ {{20210625-104833.png?nolink}} モジュールAでは乱数を生成し、モジュールA-DASHではAで作成した乱数を用いて、フラグを定義する処理を行うとします。\\ ちなみにAのローダルーチンは、 package A; sub load { my $self = shift; $self->{'RAND_A'} = int( rand(1) * 100 ); }A-DASHのローダルーチンは、package A-DASH; sub load { my $self = shift; my $rand_a = $self->{'RAND_A'}; # モジュールAの乱数を取得 my $flg_adash; if ( $rand_a > 50 ) { # 取得した乱数が50以上 $flg_adash = 0; # フラグ=0 } else { # 取得した乱数が50以下 $flg_adash = 1; # フラグ=1 } }です。 モジュールA-DASHが正常に動作するためには先にモジュールAで乱数を生成しておく必要がありますが、ローダ処理の呼び出し順は@INCによって決定しているため、モジュールAよりも先にモジュールA-DASHのローダが呼び出されると乱数を生成していないのでエラーとなります。\\ このような処理を行う場合、次のような方法で実現することができます。\\ ちなみにAのローダルーチンは、package A; sub load { my $self = shift; # ローダ処理で呼出しが行われたとき、既にモジュールAの値が # 定義済み(手動により呼出し済み)だったら、ローダルーチンを抜けます。 return unless( defined( $self->{'RAND_A'} ) ); $self->{'RAND_A'} = int( rand(1) * 100 ); }A-DASHのローダルーチンは、package A-DASH; sub load { my $self = shift; # 先にモジュールA-DASHがロードしてしまい、取得したモジュールAの値が未定義だった場合 # モジュールAのローダルーチンを手動で呼び出します。 $self->A::load() unless( defined( $self->{'RAND_A'} ) ); my $rand_a = $self->{'RAND_A'}; # モジュールAの乱数を取得 my $flg_adash; if ( $rand_a > 50 ) { # 取得した乱数が50以上 $flg_adash = 0; # フラグ=0 } else { # 取得した乱数が50以下 $flg_adash = 1; # フラグ=1 } }のように変更します。\\ モジュールA-DASHではモジュールAよりも先に呼び出された場合、取得したモジュールAの変数が未定義なので、モジュールAはロードされていないとみなしモジュールAのロードを試みます。取得したモジュールAの変数が未定義でなければ、モジュールAはロード済みなので、処理を続行します。 モジュールAのローダルーチンを手動で呼び出した場合、関数load()が再び呼び出すことになりますが、手動で呼び出したときに設定された値が関数load()の処理で再び呼び出されると新たな値に変わってしまい、その後の処理が意図しない動作を生じる可能性があるため、2回目以降の呼び出しを禁止するためにモジュールAのルーチンでは変数に乱数がすでに設定されているなら2回目以降の呼び出しが行われたとみなし、ローダルーチンを抜けるように施しています。\\