mod_perlでグローバル変数的なコーディング

このQ&Aのポイント
  • mod_perlでグローバル変数的なコーディング方法について教えてください。
  • スクリプト全体で参照したい設定値のような変数を、グローバル変数を使わずに実現する方法はありますか?
  • シンボルテーブルを指定してメインルーチンのレキシカル変数を参照する方法も考えましたが、美しくないし名前空間を侵害してしまうため、適切な方法を知りたいです。
回答を見る
  • ベストアンサー

mod_perlでグローバル変数的なコーディング

mod_perlに限ったことではないですが、グローバル変数はあまり使うべきではないとされていますよね。 しかし、スクリプト全体にわたって参照したい「設定値」のようなもの(よくある例としては、スクリプトの冒頭のほうで様々な設定をセットしておくような変数)の場合、いわば環境変数のように、複数のサブルーチンからでも必要時に参照できたほうが便利です。 このような使われ方で、かつ「おやくそく」に従ってグローバル変数を使わずに実現する方法は、ないものでしょうか。 シンボルテーブルを指定して無理やりメインルーチンのレキシカル変数を参照する、なんていう方法も考えてみましたが、どうも「美しくない」し、そもそも名前空間を侵害しているわけで、本末転倒です・・・ 皆さんはどのようにしているのでしょう。 御教授のほどお願いいたします。

  • Perl
  • 回答数4
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • bgbg
  • ベストアンサー率53% (94/175)
回答No.4

> たとえば、ModuleAで使う設定値を書いておくHogeConstants.pmには、 > package ModuleA::HogeConstants; > と書いておく、 > ModuleB用なら、 > package ModuleB::HogeConstants その例であれば両者は別物として扱われます。ただモジュールの内容はキャッシュされますので モジュールの中の変数は別のリクエストでも引き続き保持されることになります。 そのあたりは十分考慮してください。 mod_perlではグローバル変数は他のプロセスから常に読まれる可能性があります。 なので、個々の処理で値が変わる変数をグローバル変数と宣言するのは危険だと思います。 そのような変数はmyでレキシカルスコープを持たせ、グローバル変数を使わないよううまく プログラムを設計しましょう。 分かりにくい書き込みで申し訳ありませんでした。

taseki
質問者

お礼

何度もありがとうございます。 名前空間のことも理解できましたし、またおっしゃるとおり可能な限りレキシカルに、最低でもパッケージグローバル変数にすべきですね。 mod_perlはほとんど文書が英文なので苦戦していますが…、かなり面白いので頑張ってマスターしたいと思います。 お付き合いいただき本当にありがとうございました。

その他の回答 (3)

  • bgbg
  • ベストアンサー率53% (94/175)
回答No.3

どちらの方法をとるにしても、呼出しごとに別々の名前空間になるのはパッケージを指定しない部分(main)で、 useやrequireされたパッケージはずっとその名前空間でメモリ上にキャッシュされます。 (つまり、パッケージは完全に共有になります) よって、 ModuleA::HogeConstants ModuleB::HogeConstants というような名前空間は持たないと思います。 個々の呼び出しでそれぞれ値が変わるような変数は、グローバル変数にするのがやはりいいかと。 (our関数で定義するのが無難です) 書籍やWebでグローバル変数についての警告がいやっというほどあるのは、perlはバージョン4まで ある意味グローバル変数しか存在しなかった言語で、グローバル変数であることを前提とした スクリプトがたくさん出回っていました。 グローバル変数の一番の弊害は可読性の低下なので、当時のPerlスクリプトは他人が読めたもの ではありませんでした。 バージョンが5になってレキシカルスコープという局所変数に相当する変数体系が出来て、ようやく グローバル変数頼みのプログラミングから脱却できたのですが、それまでの古い情報(もしくは人) は今でも残っています。 そういった古いものに対しての注意喚起のため、本やWebサイトでの警告も残っているのでしょう。

taseki
質問者

お礼

ご丁寧なご説明いただき、ありがとうございます。 本当に何度もすみませんが… では、もし「外部ファイルに設定値を書く方法」を使いたい場合は、それぞれのHogeConstants.pmの中のパッケージ宣言自体をネストしたものにすれば、どうでしょうか。 たとえば、ModuleAで使う設定値を書いておくHogeConstants.pmには、 package ModuleA::HogeConstants; と書いておく、 ModuleB用なら、 package ModuleB::HogeConstants これなら別物として扱われますか? また、何か別の問題などあれば、ご指摘いただければと思います。 (参照する名前が長くなりすぎ、と言うのもありますが) しかし、メインのほうの名前空間がきちんと確保されるのなら、いっそのことHogeConstants.pmのほうにもpackageを書かないほうが、むしろ安全な気がしてきました…。 (そうすれば、メイン側の名前空間に入るわけですよね?)

  • bgbg
  • ベストアンサー率53% (94/175)
回答No.2

> ちなみに、そのパッケージ内でグローバル宣言しておくと言うことですか?それともアクセスメソッドのようなものを作るとか? 自分ならグローバル宣言で対応します。 use strict; しておけば変数名を間違えたときに警告が入りますから。 グローバル変数の弊害についてはすでにご理解いただいていると思いますが、ここでpackage内に 設定した変数はグローバルな変数というよりもパッケージに対してstaticな変数と考えた方が いいと思います。 名前空間をしっかり考慮していれば変数名の重複や解読性の低下は起こらないと思います。 名前空間とスコープをしっかり理解していれば「好ましくない」変数の扱い方にはならないと 思いますよ。

taseki
質問者

補足

ご回答ありがとうございます。 おっしゃるとおりですね。とりあえずは自分のやりやすい方法で良いと考え、ご提案いただいたパッケージを作る方法にしようと思います。 ただ、もう一つだけ質問させてください。 先に、グローバル変数に関する留意点を一応確認したいと思います。間違いがあればご指摘いただければと思います。 問題は主に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)
回答No.1

あくまで自分が作るなら・・・の話です。 ・グローバル的に使いたい変数専用の名前空間を作る ・環境変数(%ENV)にセットする mod_perlなら前者かなと。 (HogeConstantsみたいなパッケージ名のクラスをつくり、 $HobeConstants::foo のようにアクセス可能) Javaのインターフェースにstaticな変数を書くような感じです。 (Javaが分からなかったらごめんなさい)

taseki
質問者

お礼

ご回答ありがとうございます。 なるほど、別ファイル(とは限らないですが)にしておいて、あたかも設定ファイルのようなイメージで使えますね。 ちなみに、そのパッケージ内でグローバル宣言しておくと言うことですか?それともアクセスメソッドのようなものを作るとか? この場合グローバル宣言でも、終了時にパッケージごと破棄されるのでmod_perlでも問題はないと思いますが、「推奨」的にはどうなんでしょう? こうなってくると好みや気分の問題かもしれませんが…。 私も自分なりに考えてみましたが、ごく小さいスクリプトや別ファイルが面倒なとき用として、以下を考えました。 sub CONST {   my %value = (    name1 => value1,    name2 => value2,    name3 => value3   );   return $value{$_[0]}; } # 使うときは print &CONST('name1'); いまいちですかね…

taseki
質問者

補足

※下の続き 考えてみたら、一般的なPerlモジュールで$VERSIONなど、よくグローバル宣言されていますね。 それなら、なぜ「グローバル変数はコーディング的・構造的に好ましくない」というような解説があるのか、少々疑問です…。 極端な話、メインルーチン自体をパッケージすれば名前空間の問題もないと思うのですが…。 気にしすぎでしょうか(苦笑)

関連するQ&A

  • パッケージ内のグローバル変数

    perlでいまいち理解できないことがあります。 パッケージ内にグローバル変数を作った場合、 外部のスクリプトから完全修飾名で参照できますが、 myによるグローバル変数だけ見ることができません。 レキシカルスコープとはいえ、パッケージ内では グローバル変数にしても参照できないようです。 package MyGlobalVal use vars qw($val1); # これは外部から見える our $val2; #これも外部から見える my $val3; # これは見えない この場合、$val3は外部からなんらかの方法でアクセス 可能なんでしょうか? また参照できない理由はmy宣言により、パッケージの 名前空間とは別の場所(Cだとローカル変数はスタック上に 積まれますよね)にあるから、という理解でよいのでしょうか? アドバイスなどいただけると幸いです。

    • ベストアンサー
    • Perl
  • apache/mod_perlの実行エラーについて

    apacheについて質問です。分かる方、どうぞご教授下さい。 httpd.confにmod_perlの設定を記述しない場合、通常どおりapacheが起動するのですが、以下のようにmod_perlの設定を追記するとapacheがエラーで起動しません。 【mod_perlの設定】 PerlModule ModPerl::Registry PerlRequire /usr/lib/perl5/site_perl/5.8.8/startup.pl <Location /cgi-bin> SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlSendHeader On Options ExecCGI </Location> 【apacheのエラー内容】 /usr/local/apache2/bin/httpd: symbol lookup error: /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/auto/Apache2/ServerUtil/ServerUtil.so: undefined symbol: ap_get_server_banner httpd.confのmod_perlの設定については、他のサーバーでは問題なく起動していますので、mod_perlのconfigure時の共有ライブラリの設定に不備があるのではと思っているのですがどう設定すればいいのか分かりません。mod_perlのconfigure時のオプションは以下のようになっています。 【mod_perlのconfigure】 perl Makefile.PL \ > MP_USE_STATIC=1 \ > MP_AP_PREFIX=../httpd-2.0.63 \ > MP_AP_CONFIGURE="--prefix=/usr/local/apache2 --with-mpm=prefork" 以下、grep の実行結果です。 [root@colinux mod_perl-2.0.3]# grep -r ap_get_server_banner /usr/lib/* バイナリー・ファイル/usr/lib/httpd/modules/mod_rewrite.soは一致しました バイナリー・ファイル/usr/lib/httpd/modules/mod_proxy_connect.soは一致しました バイナリー・ファイル/usr/lib/httpd/modules/mod_proxy_ftp.soは一致しました どんな些細なことでも結構ですので、どうかご教授のほど宜しくお願い致します。 【環境】 fedora6 apache2.0.63 mod_perl2.0.4

  • MOD_PERL2.0の起動の仕方について

    以下のキーワードをDOS窓で入力して ppm install http://theoryx5.uwinnipeg.ca/ppms/mod_perl.ppd mod_perl.so(Mod_perlモジュール)をインストールしました。 そして、httpd.confに以下のコマンドを追加して、extra.plをhttpd.confと同じフォルダに置き ##Mod_perl## LoadFile "C:/usr/local/bin/perl58.dll" LoadModule perl_module modules/mod_perl.so PerlRequire "C:/Program Files/Apache2/conf/extra.pl" #Alias /perl/ "/Apache2/perl/" <Location /perl> SetHandler perl-script PerlResponseHandler ModPerl::Registry Options +ExecCGI PerlOptions +ParseHeaders </Location> ##Mod_perl## Apacheを起動してもDOS窓は、画面に何もコメントを表示しないまま閉じてしまいます。 Mod_perlモジュールをインストールしてから、Apacheを起動するには一体どの様にすれば 宜しいかどうか教えて下さい。 ちなみに私は以下URLを参照しました。 ホームサーバの構成 http://eazyfox.homelinux.org/etc/serverspec.htm Mod_perl2.0のWin32の説明 http://perl.apache.org/docs/2.0/os/win32/config.html extra.plの内容も上の両ページに書かれている内容を埋め込んでやってみましたがどちらも結果は同様です。 どうかご教授宜しくお願いします。

    • ベストアンサー
    • Perl
  • mod_perlインストール時のエラー

    mod_perl インストール中に行き詰まりました。 どこから調べて行けばよいかどなたかアドバイスお願いします。 $ make ・ ・ ld: 重大なエラー: シンボル参照エラー。libperl.so に書き込まれる出力はありません。 collect2: ld はステータス 1 で終了しました *** Error code 1 make: Fatal error: Command failed for target `libperl.so' Current working directory /export/home/Apache/mod_perl-1.29/apaci *** Error code 1 make: Fatal error: Command failed for target `apxs_libperl' ちなみに、エラーメッセージが出る前のメッセージですが以下のような感じです。 よろしくお願いします。 ・ ・ gcc -L/usr/local/lib -o libperl.so mod_perl.lo perlxsi.lo perl_config.lo perl_util.lo perlio.lo mod_perl_opmask.l o Apache.lo Constants.lo ModuleConfig.lo Log.lo URI.lo Util.lo Connection.lo Server.lo File.lo Table.lo -R /usr/ perl5/5.6.1/lib/sun4-solaris-64int/CORE /usr/perl5/5.6.1/lib/sun4-solaris-64int/auto/DynaLoader/DynaLoader.a -L/ usr/perl5/5.6.1/lib/sun4-solaris-64int/CORE -lperl -lsocket -lnsl -ldl -lm -lc 未定義の 最初に参照している シンボル ファイル main /usr/local/lib/gcc/sparc-sun-solaris2.9/3.4.6/crt1.o ap_os_dso_unload mod_perl.lo ap_null_cleanup mod_perl.lo ap_index_of_response Apache.lo ・ ・ ap_table_get mod_perl.lo ap_table_add perl_config.lo ld: 重大なエラー: シンボル参照エラー。libperl.so に書き込まれる出力はありません。 collect2: ld はステータス 1 で終了しました ・ ・

  • mod_perlのキャッシングに関して

    現在RedhatLinuxでapache+mod_perlを動かしています。 自作のモジュールXXXX.pmを使用した(useにて)CGIを動かしているのですが、XXXX.pmに変更を加えても、それが反映されません。 Apache::Registoryを設定しているのですが、.cgiはうまく再コンパイルされているようなのですが、.pmを使用するとうまくいきません。ディレクトリは同一です。 mod_perlのキャッシングのせいだと思うのですが、回避の方法がご存知の方がいましたら教えて下さい。

  • global 変数を使わないサンプルスクリプト

    今は技術・努力不足でglobal変数を多用していますが、できれば使いたくありません。 かといって、今の認識のまま、関数に引数を付け足していったら、引数が増えてしまうし、一つにまとめたものを関数内でlistで展開するのも本末転倒です。 そこでグローバル変数を使っていない、スクリプトを作っているPHPスクリプトがありましたら、教えてください。 できれば、シンプルで簡単なスクリプトが1つのものが、勉強するにはいいのですが。 また、グローバル変数を使わないテクニック、考え方を教えているHPがありましたら、お願いします。

    • 締切済み
    • PHP
  • Perlの変数宣言について

    PHPを毎日書いている者ですが、たまたまPerlのメールフォームをカスタマイズ しなければならなくなりました。 use strict宣言がある場合、変数はmyまたはlocalで宣言しなければいけないようですが、 サブルーチン内に sub form { ・・・ my ($form_value,$error_list) = @_; ・・・ print $error_list{'inquiry_type1'} としたところ、 Global symbol "%error_list" requires explicit package name at ・・・ と、宣言が無い場合に出るというエラーが出ました。 $error_listには、inquiry_type1は入っているはずなのですが、どのような 宣言をすればよいのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • mod_perlのキャッシュについて

    はじめまして、isi0033と言います。 下記のご回答宜しくお願い致します。 現在、レンタルサーバを借りてapache,mod_perlでシステムを構築しているのですが、潜在的なバグをもったプログラムにアクセスし、一度でも、ブラウザに『Internal Server Error』を表示されると、それがキャッシュとして残ってしまい、プログラムのバグを修正しても、『Internal Server Error』が表示されたりします。 何度かリロードすると正しく表示されるのですが、 とても安心して公開できません。 レンタルサーバでは、Apache::Registryが使われているようで、mod_perlについて色々調べると、Perlプログラムを読込んでコンパイルしたものをメモリにキャッシュするとありました。 このメモリをいったんクリアする設定or方法等、ご存知の人がいましたら、教えてください。

    • ベストアンサー
    • Perl
  • PerlからPHPへ移行したときの注意事項は

    PerlからPHPに移りまして、戸惑うことがあります。 Perlでは、 use strict; my $hensuu = 1; とレキシカル変数としなければ、変数未宣言となり スペル間違いの変数の使用が避けられるのですが、 PHPでは、 $hensuu = 1; と、何の設定もなく、利用時に $hensu += 0; としても問題なく動作します。 これって危険なのですが、みなさんはどう対処していますか? あと、PerlからPHPにソース移行する場合に 気をつけないことがありましたら、教えてください。

    • ベストアンサー
    • PHP
  • mod_rewriteの環境変数を埋め込みたい

    お世話になります。 現在、以下の環境でWebアプリケーションを開発しています。 CentOS5.4 Apache2.2.3 Tomcat7 JavaSE6 ApacheとTomcatの連携にmod_proxy_ajpモジュールを使用しています。 ただ、クライアントからアクセスするURLと連携先のURLが異なるため、Java側でHttpRequestからコンテキストパス以降を取得するとajp連携されたパスしか取得できず、クライアントがアクセスしたURI情報が取得できません。 これを対策するために、Apacheモジュールのmod_rewriteとmod_headersを利用して、 クライアントがアクセスしたURIをリクエストヘッダに埋め込もうとしています。 以下httpd.confに追加した設定です。 (rewrite.confも試しました) RewriteEngine On RewriteRule .* - [E=ORG_QUERY_STRING:%{QUERY_STRING}] RequestHeader append "test_query_string" %{ORG_QUERY_STRING}e 設定後、Apacheを再起動してWebアプリケーションにアクセスすると、リクエストヘッダ自体は追加されているのですが値が(null)となってしまい取得できません。 mod_rewriteの環境変数が取得できていないのかと思い、 RewriteRule .* - [E=ORG_QUERY_STRING:TEST] と固定文字列を埋め込んでも取得できませんでした。 このことからENVによる環境変数への設定、または参照が出来ていないのかと思われますが、どうにも解決できません。 参照時に RequestHeader append "test_query_string" %{ENV:ORG_QUERY_STRING}e としても同様の結果でした。 心当たりのある方、またはデバッグ方法や別解などアドバイスを頂けないでしょうか? なお、httpd.confではmod_rewrite、mod_headersのモジュール定義は有効となっております。 また、環境変数のスペルミスもコピペして確認しております。

専門家に質問してみよう