- ベストアンサー
mod_perlでグローバル変数的なコーディング
- mod_perlでグローバル変数的なコーディング方法について教えてください。
- スクリプト全体で参照したい設定値のような変数を、グローバル変数を使わずに実現する方法はありますか?
- シンボルテーブルを指定してメインルーチンのレキシカル変数を参照する方法も考えましたが、美しくないし名前空間を侵害してしまうため、適切な方法を知りたいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
> たとえば、ModuleAで使う設定値を書いておくHogeConstants.pmには、 > package ModuleA::HogeConstants; > と書いておく、 > ModuleB用なら、 > package ModuleB::HogeConstants その例であれば両者は別物として扱われます。ただモジュールの内容はキャッシュされますので モジュールの中の変数は別のリクエストでも引き続き保持されることになります。 そのあたりは十分考慮してください。 mod_perlではグローバル変数は他のプロセスから常に読まれる可能性があります。 なので、個々の処理で値が変わる変数をグローバル変数と宣言するのは危険だと思います。 そのような変数はmyでレキシカルスコープを持たせ、グローバル変数を使わないよううまく プログラムを設計しましょう。 分かりにくい書き込みで申し訳ありませんでした。
その他の回答 (3)
- bgbg
- ベストアンサー率53% (94/175)
どちらの方法をとるにしても、呼出しごとに別々の名前空間になるのはパッケージを指定しない部分(main)で、 useやrequireされたパッケージはずっとその名前空間でメモリ上にキャッシュされます。 (つまり、パッケージは完全に共有になります) よって、 ModuleA::HogeConstants ModuleB::HogeConstants というような名前空間は持たないと思います。 個々の呼び出しでそれぞれ値が変わるような変数は、グローバル変数にするのがやはりいいかと。 (our関数で定義するのが無難です) 書籍やWebでグローバル変数についての警告がいやっというほどあるのは、perlはバージョン4まで ある意味グローバル変数しか存在しなかった言語で、グローバル変数であることを前提とした スクリプトがたくさん出回っていました。 グローバル変数の一番の弊害は可読性の低下なので、当時のPerlスクリプトは他人が読めたもの ではありませんでした。 バージョンが5になってレキシカルスコープという局所変数に相当する変数体系が出来て、ようやく グローバル変数頼みのプログラミングから脱却できたのですが、それまでの古い情報(もしくは人) は今でも残っています。 そういった古いものに対しての注意喚起のため、本やWebサイトでの警告も残っているのでしょう。
お礼
ご丁寧なご説明いただき、ありがとうございます。 本当に何度もすみませんが… では、もし「外部ファイルに設定値を書く方法」を使いたい場合は、それぞれのHogeConstants.pmの中のパッケージ宣言自体をネストしたものにすれば、どうでしょうか。 たとえば、ModuleAで使う設定値を書いておくHogeConstants.pmには、 package ModuleA::HogeConstants; と書いておく、 ModuleB用なら、 package ModuleB::HogeConstants これなら別物として扱われますか? また、何か別の問題などあれば、ご指摘いただければと思います。 (参照する名前が長くなりすぎ、と言うのもありますが) しかし、メインのほうの名前空間がきちんと確保されるのなら、いっそのことHogeConstants.pmのほうにもpackageを書かないほうが、むしろ安全な気がしてきました…。 (そうすれば、メイン側の名前空間に入るわけですよね?)
- bgbg
- ベストアンサー率53% (94/175)
> ちなみに、そのパッケージ内でグローバル宣言しておくと言うことですか?それともアクセスメソッドのようなものを作るとか? 自分ならグローバル宣言で対応します。 use strict; しておけば変数名を間違えたときに警告が入りますから。 グローバル変数の弊害についてはすでにご理解いただいていると思いますが、ここでpackage内に 設定した変数はグローバルな変数というよりもパッケージに対してstaticな変数と考えた方が いいと思います。 名前空間をしっかり考慮していれば変数名の重複や解読性の低下は起こらないと思います。 名前空間とスコープをしっかり理解していれば「好ましくない」変数の扱い方にはならないと 思いますよ。
補足
ご回答ありがとうございます。 おっしゃるとおりですね。とりあえずは自分のやりやすい方法で良いと考え、ご提案いただいたパッケージを作る方法にしようと思います。 ただ、もう一つだけ質問させてください。 先に、グローバル変数に関する留意点を一応確認したいと思います。間違いがあればご指摘いただければと思います。 問題は主に2つ。 1.staticであること。初期化に関する問題。前回実行時の値が残る。(きちんと初期化処理をすれば良い。) 2.名前の競合。同プロセスに常駐するときに衝突する。 で、このような問題は、実行形態に依存すると思うのですが、つまり既存のスクリプトをCGI的に動かすApache::Registry からの呼び出しなのか、それともハンドラとして呼び出すのか、という違いです。 ●Apache::Registryの場合は、名前の衝突を避けるためにURIから生成した名前空間が作られ、その下で実行されるため、(良い悪いは別にしても)基本的には名前の競合は起きないように思います。(逆に環境変数は共有されるので、スクリプトの数が多くなるとやはり危険?) ●ハンドラとして呼び出された場合、そもそもモジュールですから、通常ならこれ自体がパッケージ化されているはずなので、やはり競合が起きるとは考えにくいと思います。 そう考えると、やはりグローバル変数は、ある程度気をつけてさえいれば、それほど気にしなくても良いような気がしてきています。というより実際のところ問題が起きることは多くないような気がするのですが…。 本やその他で必ずと言っていいほど警告しているので、逆に疑問なんですよね…。 また、質問文に書いたような設定値をセットしておきたいようなケースと言うのは、ほとんど既存のスクリプトをApache::Registryから使う場合だと思うのですが、もしハンドラのほうでも使いたい場合、useでロードしたパッケージも(HogeConstantsも)常駐される、そうなると、同じ方法をとる(HogeConstantsという名前を使う)モジュールをいくつも作ったらHogeConstantsというパッケージが複数になってしまい、やはり競合する、ということなのでしょうか。 もしそうなら、いちいち名前を変えるしかない、ということになりますか? 正直、mod_perlがまだ良く解っていないのですが…、プリロードするのではなくハンドラからuseしたものは通常のPerlのようにネストされたパッケージになり、 ModuleA::HogeConstants ModuleB::HogeConstants というように、2つは別の名前空間を持つ、つまり問題ないのでしょうか。 ※文字数制限のため、「補足」欄に投稿しました。
- bgbg
- ベストアンサー率53% (94/175)
あくまで自分が作るなら・・・の話です。 ・グローバル的に使いたい変数専用の名前空間を作る ・環境変数(%ENV)にセットする mod_perlなら前者かなと。 (HogeConstantsみたいなパッケージ名のクラスをつくり、 $HobeConstants::foo のようにアクセス可能) Javaのインターフェースにstaticな変数を書くような感じです。 (Javaが分からなかったらごめんなさい)
お礼
ご回答ありがとうございます。 なるほど、別ファイル(とは限らないですが)にしておいて、あたかも設定ファイルのようなイメージで使えますね。 ちなみに、そのパッケージ内でグローバル宣言しておくと言うことですか?それともアクセスメソッドのようなものを作るとか? この場合グローバル宣言でも、終了時にパッケージごと破棄されるのでmod_perlでも問題はないと思いますが、「推奨」的にはどうなんでしょう? こうなってくると好みや気分の問題かもしれませんが…。 私も自分なりに考えてみましたが、ごく小さいスクリプトや別ファイルが面倒なとき用として、以下を考えました。 sub CONST { my %value = ( name1 => value1, name2 => value2, name3 => value3 ); return $value{$_[0]}; } # 使うときは print &CONST('name1'); いまいちですかね…
補足
※下の続き 考えてみたら、一般的なPerlモジュールで$VERSIONなど、よくグローバル宣言されていますね。 それなら、なぜ「グローバル変数はコーディング的・構造的に好ましくない」というような解説があるのか、少々疑問です…。 極端な話、メインルーチン自体をパッケージすれば名前空間の問題もないと思うのですが…。 気にしすぎでしょうか(苦笑)
お礼
何度もありがとうございます。 名前空間のことも理解できましたし、またおっしゃるとおり可能な限りレキシカルに、最低でもパッケージグローバル変数にすべきですね。 mod_perlはほとんど文書が英文なので苦戦していますが…、かなり面白いので頑張ってマスターしたいと思います。 お付き合いいただき本当にありがとうございました。