電子書籍の厳選無料作品が豊富!

Perl 初心者です。初めて質問します。

test_sub.pl で宣言した変数を test_main.pl から参照したくて悩んでいます。

環境 : WindowsXP / ActivePerl 5.14.2


--------------------
* test_sub.pl
--------------------
#!/usr/bin/perl
use strict;

our $hoge = 'HOGE';

1;
--------------------
* test_main.pl
--------------------
#!/usr/bin/perl
use strict;

require 'test_sub.pl';

print "Content-type: text/html\n\n";
print $hoge;
--------------------

これを実行すると、
Global symbol "$hoge" requires explicit package name at C:/public_html/cgi-bin/test_main.pl line 7.\r
というエラーが出ます。

require する前に、test_main.pl のほうで our($hoge); と宣言したり
参照する際に print $main::hoge; とパッケージを指定したりすればいけるのですが、
これらをしないとできないものなのでしょうか。

use strict; を書かなければ最初のソースでも動くのですが use strict は書きたい…

継承のようなことをしたいのです。

ちなみに以下試してみたソースです。

--------------------
* test_main.pl
--------------------
#!/usr/bin/perl

########################################
# NG
use strict;

require 'test_sub.pl';

print "Content-type: text/html\n\n";
print $hoge;

########################################
# OK our変数を宣言しておくといける
=pod
use strict;

our ($hoge);
require 'test_sub.pl';

print "Content-type: text/html\n\n";
print $hoge;
=cut

########################################
# OK 参照する際にパッケージ名を指定すればいける
=pod
use strict;

require 'test_sub.pl';

print "Content-type: text/html\n\n";
print $main::hoge;
=cut

########################################

########################################
# NG
=pod
use strict;

use base qw(test_sub);

print "Content-type: text/html\n\n";
print $hoge;
=cut

########################################
--------------------
* test_sub.pm
--------------------
#!/usr/bin/perl
package test_sub;
use strict;

our $hoge = 'HOGE';

1;
--------------------

NG パタンはどちらも Global symbol "$hoge" requires explicit package name のエラーとなります。

もしご存じの方がいらっしゃいましたら教えてください。
よろしくお願いします。

A 回答 (1件)

端的に言えば「our するなりパッケージで修飾するなりしてください」となります.



詳細はこんな感じ:
このエラーはコンパイル時のエラーであって実行時のエラーではありません. つまり, 実行に先立つコンパイルのときに「use strict が有効なのに my も our も state もされていない (かつパッケージ名での修飾もされていない) 変数 $hoge が現れた」というエラーです.

「require されたファイルの中に our がある」のは確かですが, 次の 2つの理由によりそれは影響しません:
・use とは異なり, require によるファイルの取り込みは実行時に行われます. つまり
require 'test_sub.pl';
とあってもコンパイラは test_sub.pl の中は見ません. したがって「test_sub.pl の中の our」はコンパイル時には影響を与えません.
・また, our の有効範囲はレキシカルスコープに制限されています. そして「1つのソースファイル」はレキシカルスコープとなりますから, require をコンパイル時に行っても「test_sub.pl の中の our」は test_sub.pl の中 (もちろん our 以降の) でしか有効ではありません.

余談ですが, use strict もレキシカルスコープで有効となります. つまり, 「test_sub.pl の中の use strict」はそれを require した test_main.pl では無効です (し, 逆に require する前に test_main.pl で use strict してもそれは test_sub.pl には影響しません)
    • good
    • 0
この回答へのお礼

> 端的に言えば「our するなりパッケージで修飾するなりしてください」となります.

やはりそうですか… ありがとうございます。

# パッケージで装飾のほうが良いかな… test_sub のほうで変数名変えられたりすると危ないし
# どうせパッケージで装飾するなら main じゃなくてちゃんと package 宣言しようかな


説明していただいた内容もすごくわかりやすかったです。

> use とは異なり, require によるファイルの取り込みは実行時に行われます

これについてはちらっと見かけたので use test_sub; にしてみたりもしたのですが
エラーが取れずもやもやしていました。が

> また, our の有効範囲はレキシカルスコープに制限されています.
> そして「1つのソースファイル」はレキシカルスコープとなりますから ...

この辺が絡んでくるのですね。理解しました。


とても助かりました。ありがとうございます m(_ _)m

お礼日時:2012/02/16 16:30

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!