Perl/CGIプログラムの局所化の宣言
今回の学習テーマは、「Perl/CGIプログラムの局所化の宣言」についてです。
編集前記
今回の編集前記は前々回の続きで、プログラミング能力上達のためには、具体的にどんなイメージを持てばよいかについて個人なりの意見を書いてみたいと思います。
Perl/CGIプログラミング学習 のタイミングと、記事のスペースの関係上、掲載予定がひとつずれて今回お話しすることになりました。
読んでいただけるとわかりますが、編集前記とはいえそれなりの量がありますから、前回の学習量では掲載できなかったことがわかるかと思います。
話の流れがわからない場合は、 前々回のPerl/CGI学習 を読み返していただくか、適当に読み飛ばしてください。
まぁそうは言っても、ばっさり切り捨てるのもなんなので、今までの話の流れを簡単に言ってしまうとこんな感じです。
プログラミング能力上達に不可欠な要素として、個人的に重要視している考え方というのがありまして、結論としてそれは、「物事の構造をイメージする力を身につけること」ということなのです が…。
これはプログラミングの世界に限らず、普通に社会生活を営む上で持っていると役に立つ能力です。
ではこれをプログラミングの世界に持ってきたとき具体的にどんな感じのイメージを持っていればよいのかということについて、今回お話しすると言いました。
なので、ここでお話ししなくてはいけないというわけです。
これ以外にも、プログラミング技術上達の要素はたくさんあります。
10人いれば10通りの考え方があってもおかしくない話ですから、この考え方がすべてではありません。
そんなことはわかりきっていますので、あくまでも個人的な意見として聞いていただければ嬉しいです。
これでみなさん、やっと同じラインに立つことができました。
話の進め方がかなり強引だということはわかっていますので、あえて突っ込んでくれなくてもいいです(苦笑)。
では本題です。
あなたのプログラミング技術向上のための、プログラムのイメージ方法についてアドバイスします。
まずは、プログラムのイメージとは、具体的に一体何なのかですが…。
それは、「ひとつの目的を達成するために必要な細かいプロセスの組み立て」です。
ひとことで表現するとものすごく無理がありますが、あえて表すならこんな感じですね。
ではもっと具体的に、「ひとつの目的を達成するために必要な細かいプロセスの組み立て」とは一体何なのかについてお話します。
まずは、この連載で何度となく言っていることなのですが、プログラムというのは細かい動作の集合体にすぎません。
そして以前、プログラムが行っている動作についてお話したことがありましたよね。
たとえどんなに大きく複雑なプログラムであっても、その動きを細分化していったら、すべて3種類の動きに分類できるんですよという話です。
覚えていますか?
連載の最初の頃ではなく、最近の話ですから、覚えていただいていればうれしいのですが(苦笑)。
まぁ、忘れてしまった人や、そのころこの連載を読んでいない人もいるので、ここで改めてお話ししますね。
はじめて聞いたという場合は、ぜひ覚えておくと後々役に立つ話です。
プログラムの動きを細分化すると、主に3種類の動作に分類することができます。
1つ目は、直線的動き。
2つ目は、分岐的動き。
3つ目は、ループ的動き。
直線的動きとは、プログラムファイルの上から下へひたすらまっすぐに、処理が実行されていくタイプの動きです。
分岐的動きとは、あるポイントを境に、異なった処理が行われるタイプの動きです。
ループ的動きとは、ある条件に従い、指定された動作を繰り返すタイプの動きです。
プログラムとは、この3種類の動きの組み合わせでできています。
ですから、プログラミングとは、ある目的達成のために組み上げるパズルのようなものです。
そしてこのパズルの1ピース1ピースに当たるのが、前述しました3種類の動きだというわけです。
ここまでくると、もうおわかりですよね。
プログラムの構造をイメージするというのは、この3種類の動きをそれぞれイメージし、完成図を組み立てていくということです。
プログラムの動きの基礎となる3種類の動きをイメージし、ある目的を達成するにはどんな風に組み合わせていったらよいかを考えるわけです。
「これとこれを組み合わせてこんな感じかな?」とか…
「この機能を追加するには、ここからこっちにつなげて、その後こっちに処理を回せばいいか」などなど、頭の中で基礎的なイメージを組み上げるのです。
当然、目的が単純なものであればパズルも単純なものになりますし、目的が複雑なものであれば、組み立てるパズルも複雑なものになります。
いろんなものにたいして、この考えで練習し続けてみてください。
すると確実に、あなたのプログラミング能力は向上します。
練習し続けた場合、具体的に何がどうなるのかというと、頭の中で組み立てるプログラムのイメージが早く完成するようになります。
プログラミング学習を始めたばかりなので、まだイメージしたプログラムを作成できるかどうかは別にして、プログラムの流れを捉えることはできます。
プログラムの流れさえ捉えてしまえば、あとはそれを、プログラムコードに書き起こすだけですから簡単です。
プログラミングを学習し始めたころというのは、どうしてもプログラムコードを書くことばかりに意識が向いてしまいます。
ですから、ここでプログラムの流れをつかむことが大切といわれても、いまいち理解できないかもしれません。
プログラミングを学習し始めたころというのは、プログラムコードを正しく書くことに集中してしまいますからね。
でも少し余裕が出てくるとわかるんですが、プログラムコードが書けるかどうかというのは、単純に関数をどれだけ知っているのかというだけの話なんですよね。
つまり、プログラムコードを書くだけだったら、これから登場するであろう関数をたくさん学習し、プログラミング経験を積んでいけば自然と書けるようになります。
でも、プログラミングって、プログラムコードを書くだけじゃないんですよ。
プログラムコードを書くその前に、どんな動きをするプログラムにしていくのかという設計段階というのが必ずあるんです。
わかりやすく例えるなら、日曜大工をイメージしていただければわかります。
のこぎりで木を切ったり、くぎを打ちつけることができるというのは、プログラムコードが書けるということに等しいです。
作業に無駄がなく、完成したものが美しけでば、何でも作れる気がしますよね。
でも、その錯覚で作れるものというのは、自分勝手な小さなものだけです。
なぜならそこには、目的を満たすような設計がないからです。
設計図なしではまず、大きなものは作れません。
たとえ小さなものでも、寸法を測っておかないとなんとなくでしか使えません。
この目的を満たすための設計というのが、プログラム設計ですね。
プログラム設計がないと、つねに、いきあたりばったりのプログラムしか作れないというわけです。
そしてそのプログラム設計を強化するために、基礎となる3種類の動きをイメージ化し、頭の中で素早く組み立てるという力が必要なのです。
個人的なプログラマー経験から言わせてもらうとこんな感じです。
今理解できなくても、そのうちわかってくると思います。
そのときは、ぜひこのページのことを思い出してくださいね(笑)。
それでは、今回のPerl/CGIプログラミング学習に移りましょう。
変数の局所化
局所化とは簡単に言ってしまうと、「その場所だけ」という意味です。
われわれの生活でも、天気予報とかで「局所的な大雨」などと使いますよね。
あの使い方と同じです。
つまり、 Perl/CGIプログラムの変数 を、局所的に使っていきましょうというのが今回の学習テーマです。
でも、 Perl/CGIプログラム の基本機能として、「変数はいつでも必要に応じて作成することができ、どこからでも参照できる」というのがありましたよね。
今まで登場してきましたPerl/CGIのサンプルプログラムでも、必要な時にいきなり変数名を宣言して作成したり、変数を参照したい場所で自由に参照してきました。
この、「変数をどこからでも参照できる」という基本的な機能に制限をかけて…。
「変数を局所化して利用する」という仕組みに切り替えていきましょうというのが今回のお話です。
一度作成した変数をどこでも参照できるというのは、一見便利そうな感じがしますが、実は結構不便だったりします。
具体的にいつどこで、不便になるのかと言いますと…。
それは、Perl/CGIプログラム自体が大きくなったときです。
Perl/CGIプログラムが大きくなると、単純にどこでどんな名前の変数を使用したのかを忘れてしまうのです(苦笑)。
趣味でちょっと大きなPerl/CGIプログラムを作ったことのある人なら一度は経験あると思います。
「そんなバカな~」っと思うかもしれませんが…。
こんなネタみたいな話というのは意外とたくさんの人が経験しているはずです。
あなたにも、一度ぐらいは経験しておいてほしかったり、してほしくなかったり、ちょっと微妙な気持ちです(苦笑)。
特にPerl/CGIプログラムの変数名というのは、大文字と小文字を区別しますから、使用用途によって同じ名前の変数を使用するということが起こりやすいわけです。
一度使ってしまった変数だということに気づかず、あっちでもこっちでも使ってしまうんですね。
ちょっと大きめのPerl/CGIプログラムを作ったことのない場合でも、想像してみればわかります。
先ほども書きましたが、Perl/CGIプログラムの基本機能として、一度作成した変数というのは、どこからでも自由に参照したり操作することができるようになっています。
もしこの「変数をどこでも参照できる」というルールの下で、ちょっと大きなPerl/CGIプログラムを作成しようと思うものなら…。
一度でも使用した変数というのは、二度と別用途では使えません。
したがって、すべての変数名をプログラマー側で覚えておかなくてはいけないということになります。
あなたも実際にやってみるとわかりますが、これは結構きついですよ。
地獄のルールと言ってもいいですね。
そしてもし、誤って同じ名前の変数を別の用途で使用してしまった場合には、世にも恐ろしいバグが発生するかもしれないのです。
こうなると逆に不便ですよね。
まだ、数百ステップぐらいの小さなプログラムであれば、どんな名前の変数を、どんな用途で使用したのかを覚えているかもしれませんが…。
数千ステップを超えてくると、まず無理でしょうね。
さらに一人ではなく数人でプログラムを作成するとなると、同じ名前の変数を使用しないということは、よっぽど綿密にルールを決めておかないとまず無理でしょう。
仕事でPerl/CGIプログラムを作成する場合は、仕様書を作りますから、もし変数名が重複したとしても、コーディングの前にそのミスを発見できます。
でも、個人的な趣味の場合は、いちいち仕様書なんて作りませんよね。
まぁ、作っている人もいるかもしれませんが、面倒ですからね…
そんなことをしていては面倒なので、そうならないように「変数を局所化する」という考え方が出てきたわけです。
変数を局所化するということは、変数を参照したり操作できる範囲を、ある特定の範囲内にのみ限定させるということです。
つまり、変数の有効範囲を決めてしまえば、その変数の有効範囲外であれば同じ変数名を作成して別用途で使用することができるというわけです。
では具体的に、その局所化という概念は、Perl/CGIプログラムの世界ではどこで使うのかというと、主にサブルーチンを作成管理するときに登場します。
サブルーチンとは 、前回こってり説明しましたから、もう二度と説明しません(苦笑)。
まぁそのこってり解説を読んでいない人のために、サブルーチンがなんであるかを一言で説明しますと…。
サブルーチンとは、何か特定の動作を行うPerl/CGIプログラムをひとまとまりつまり、ブロック化したもののことです。
ひとつのPerl/CGIプログラムファイルが複数のブロックつまり、サブルーチン化されていると、作成管理がものすごく楽になるのです。
局所化の概念が登場する部分はほかにもあります。
それは、ifやforeachなど、限定的な扱いを必要とする部分です。
if関数やforeach関数についても、もうわかっていますよね。
これも以前学習済みになっています。
if関数は、条件分岐 のときに使います。
その時の状況によって、その後の処理を切り替えるときに使います。
foreach関数はループ させたいときに使います。
指定した数のぶんだけ、同じ処理を繰り返し実行するときに使います。
ほかにもありますがこれらはすべて、Perl/CGIプログラムの中では局所化されるエリアになります。
局所化というとなんだかわかりにくい感じがしますが、ようするに、そこだけでもなんとなく処理が成り立ってしまうような部分のことです。
もう少し具体的に表すなら、Perl/CGIプログラムでは、「{」から「}」内の部分にあたります。
前述しましたサブルーチンも、if関数も、foreach関数も、「{」と「}」を使いますよね。
ほかにもまだまだありますがそれらはすべて、「{」から「}」内で、ある程度処理が完結するようになっていますよね。
もちろん細かい例外もいくつかありますが、おおまかなイメージはつかめたかと思います。
そして、ここからが本題です。
この「{」から「}」内という局所的なエリアでのみ、有効な変数を、これからは扱っていきましょうというのが今回のメインテーマです。
では具体的に、どうすればよいかというと…。
そこでやっと、前回登場しました「my」と「local」が出てくるわけです。
前回、次回は「my」と「local」について学習すると言いましたよね。
その次回というのが今回です(笑)。
Perl/CGIプログラミングで、変数の有効範囲を指定するものが、「my」や「local」なのです。
変数を使用する前に、「my」や「local」をつけると、変数の有効範囲を宣言したことになります。
つまり、「{」から「}」内で、変数を宣言する前に「my」や「local」をつけると…。
変数の有効範囲を、「{~}」内のみに限定できるというわけです。
若干例外的なものはあるにはありますが、だいたいこの考え方で大丈夫です。
次は、もう少しプログラミング用語を用いて解説していきます。
<戻る>
ローカル変数とグローバル変数
ローカル変数とは、前述したようなある一定の範囲内でのみ有効な変数のことです。
これに対してグローバル変数とは、プログラムファイル内であればどこでも参照可能な変数のことです。
つまり、Perl/CGIプログラムでは…。
ローカル変数とは、変数が宣言されたときに「my」や「local」が頭に付けられた変数のことです。
グローバル変数とは、ローカル変数の逆で、変数が宣言されたときに「my」や「local」が頭に付けられなかった変数です。
もしくは、「my」や「local」が付いていても、その有効範囲が大きい変数のことです。
すでに何度か説明していることなので、わかりますよね。
それでは次に、Perl/CGIプログラムを使って解説します。
ローカル変数とグローバル変数を使った例です。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
&routine1;
&routine2;
sub routine1 {
my $a = 2;
print $a;
}
sub routine2 {
print $a;
}
exit;
このPerl/CGIプログラムを実行すると、「2」と表示されます。
「22」とは表示されません。
なぜかというと、同じ「$a」という変数名が使われていても…。
サブルーチン「&routine1」の「$a」はローカル変数。
サブルーチン「&routine2」の「$a」はグローバル変数。
このように別物だからですね。
サブルーチン「&routine1」の変数「$a」は、初めて登場したときつまり、変数名が宣言されたときに「my」が付けられています。
ということは、この変数「$a」を参照できる範囲というのは、サブルーチン「&routine1」内だけに限定されます。
次に、もうひとつのサブルーチン「&routine2」にある変数「$a」には、「my」が付いていないので、どこからでも参照できますが…。
サブルーチン「&routine1」の変数「$a」には、「my」が付いていますから、サブルーチン「&routine2」からは参照できないのです。
ということは、サブルーチン「&routine2」の変数「$a」というのは、宣言と同時にprint関数で出力されているということになるわけです。
つまり、サブルーチン「&routine1」の「print $a;」では、「2」が表示されますが…。
もうひとつのサブルーチン「&routine2」の「print $a;」では、なにも表示されないので、「22」とは表示されなかったわけです。
では次に、「22」と表示させてみましょう。
少し改造して「22」と表示させるには、2つの変数「$a」をグローバル変数にするのが簡単です。
つまり、今までは別物だった変数「$a」を、同じ物として解釈させるわけです。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
&routine1;
&routine2;
sub routine1 {
$a = 2;
print $a;
}
sub routine2 {
print $a;
}
exit;
このPerl/CGIプログラムを実行すると、「22」と表示されます。
このあたりの理屈は、理解していただけましたでしょうか?
わからない場合は何度か読み返して学習しておいてくださいね。
次は、もうすこしひねったローカル変数の学習です。
どんなひねりを加えるのかというと…。
ローカル変数は、宣言する場所によってサブルーチン内だけが有効範囲ではないという学習をしていきます。
ここであれこれ説明してもイメージできないと思うので、実際のPerl/CGIプログラムを使って解説します。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
$result = 'ready';
&routine;
sub routine {
$a = 2;
if ($a > 1) {
my $result = 'YES';
} else {
$result = 'NO';
}
print $result;
}
exit;
このPerl/CGIプログラムを実行すると、「ready」と表示されます。
「YES」とは表示されません。
なぜだと思いますか?
それは、前述したようにローカル変数は、「{」から「}」内であれば、サブルーチンではなくてもよいからです。
今回の場合では、確かに条件分岐のif文が成立し、変数「$result」に「YES」が格納されます。
しかし、その変数「$result」というのは、はじめてif文の「{~}」の中に登場したときに、「my」で縛りをかけられています。
if関数であろうとサブルーチンであろうと、「{~}」内で初めて登場したときに、頭に「my」が付けられていたら、それはその中だけのローカル変数になります。
ということは、if文内で「my $result」と宣言された瞬間、新たにローカル変数「$result」が誕生したことになるのです。
結論として、「YES」が格納された変数「$result」というのは、if関数の「{~}」内だけのローカル変数であり…。
最終的に表示されている変数「$result」というのは、最初に登場している同名のグローバル変数だということです。
だから「YES」ではなく、「ready」と表示されたというわけです。
なんだか少しややこしいですが、慣れてしまえば簡単ですから、たくさん使って早く慣れておくとよいですよ。
ここでいきなり問題です。
仮に、if文が成立しなかった場合は、何が表示されると思いますか?
例えば、「$a = 2;」ではなく…
「$a = 1;」だった場合、if文が成立しなくなりますよね。
そうすると、表示結果はどうなるのかという話です。
ちょっと、練習問題のつもりで考えてみてください。
答えはわざわざ発表しなくても、上のプログラムを書き換えて実行させればわかりますから、わからない場合は試してみてください。
myとlocalの違い
ここでは、Perl/CGIプログラミングにおける、myとlocalの違いについて学習していきましょう。
myとは、Perl5から実装された関数です。
それまでは、「local」が使われていました。
ここで言うPerl5とは、Perlパッケージのバージョン5という意味です。
Perlパッケージとは、最初のころ説明しましたが、一言で言うとPerlプログラムコードから実際のプログラムファイルに変換してくれるシステムのことです。
そのPerlパッケージバージョン5から登場したのがmy関数です。
Perl5以前のPerlプログラムでは、local関数を当たり前に使っていたわけです。
ですから、Perl4が主流の頃に開発されたPerl/CGIプログラムというのは、myではなくlocalが使われているはずです。
そしてこの記事を書いている今は、Perl5が主流となり、localではなくmyが使われるようになりました。
簡単にmyとlocalの歴史をお話しするとこんな感じです。
次は、myとlocalに関する用語について少し解説しておきます。
myを使って定義された変数のことを、Perlプログラミングの専門用語でレキシカルスコープ変数といいます。
そして、myを使って変数を宣言することを、レキシカルスコープ宣言といいます。
これに対して、localを使って定義された変数のことを、Perlプログラムの専門用語でダイナミックスコープ変数といいます。
そして、localを使って変数を宣言することをダイナミックスコープ宣言といいます。
ぶっちゃけ知っていても何の役にも立ちませんが、興味があれば覚えておいてください(苦笑)。
Perlプログラミング関連の見聞に触れていると、もしかしたら出てくるかもしれないという程度の用語です。
そして次はいよいよ本題の、「結局myとlocalは何が違うの?」という誰もが気になる疑問について解説していきます。
このあたりは、Perl5以前のプログラムを改造するときに必要となる知識ですから、覚えておいて損はないですよ。
今も普通にmyではなく、localが使われているPerl/CGIプログラムはありますからね。
それでは、myとlocalの違いについて解説します。
例えば、myを使った以下のようなPerl/CGIプログラムがあったとします。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
$a = 1;
&routine1;
sub routine1 {
my $a = 2;
&routine2;
}
sub routine2 {
print $a;
}
exit;
このPerl/CGIプログラムを実行させると、「1」と表示されます。
そして次に、「my」の部分を、「local」に変えてみます。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
$a = 1;
&routine1;
sub routine1 {
local $a = 2;
&routine2;
}
sub routine2 {
print $a;
}
exit;
今度は「2」と表示されます。
同じPerl/CGIプログラムなのに、myを使用したときと、localを使用したときとでは、明らかに違う結果になるわけです。
このあたりを理解しておかないと、Perl/CGIプログラムが思うように動いてくれない原因になります。
しかし、現在ではlocalではなく、myを使用するのが普通ですから、myで統一するようにしておくと楽です。
localが使われている以前のPerl/CGIプログラムを、扱う時には注意しましょう。
これで、今回のテーマ「変数の局所化について」の学習は以上です。
編集後記
今回は、ローカル変数とグローバル変数の違いについてと、myとlocalの違いについて学習しました。
ローカル変数とグローバル変数について、念のために書いておきますが、どちらが良いとかいう話ではないですから、そのあたりを誤解しないように注意してくださいね。
作成していくPerl/CGIプログラムの性質を考えて、適切なタイプの変数を使っていきましょうという話です。
前回書きましたが、なるべく独立させたいサブルーチン内では、ほとんどすべてローカル変数になりますし…。
そうでない場合は、グローバル変数を混ぜつつプログラミングした方が便利なこともあるので、しっかり理解した上で使い分けていきましょう。
myとlocalの違いについては、Perl/CGIプログラム動作が変わってくる場合もあるので、その使い方には注意しましょう。
最後に、myで変数を局所化してプログラミングする際、知っておくと便利なコーディング方法を紹介しておきます。
それは、Perl/CGIプログラムのすべての変数を局所化して扱いたいときに、役に立つ方法です。
何度も書いていますが、Perl/CGIプログラムというのは、いきなり変数名を宣言して使用することができましたよね。
ということは、Perl/CGIプログラム内で使用する変数をすべて局所化して作りたいと思っている場合は、変数名にはかなり注意しないといけません。
なぜなら、もし変数名を間違った場合、その変数は自動的にグローバル変数となってしまうからですね。
それ以前に、プログラムのバグつまり、誤動作につながりますから、ローカル変数を意識していなくても注意するのは当然なのですが(苦笑)。
まぁそうは言っても、すべての変数名に気を配りつつプログラムを作成していくのは大変ですよね。
そこで、Perl/CGIプログラムには、変数の局所化宣言をチェックする仕組みが備わっています。
この仕組みを使って、Perl/CGIプログラムを作成していけば、簡単に変数の局所化具合をチェックしてくれます。
つまり、あるPerl/CGIプログラム内で、初めてその変数が登場しているにもかかわらず、myが頭についていない場合はエラーを出すようにできるということです。
こうしておくと、Perl/CGIプログラム内での変数名の間違いをなくすことができます。
例えばこんな感じでコーディングします。
#!/usr/bin/perl
use strict;
print "Content-type: text/html\n\n";
my $abc = 'CGI Script';
print $abc;
exit;
このPerl/CGIプログラムを実行させると、「CGI Script」と表示されます。
今までと違うところは、Perlパスの下ぐらいに「use strict;」という命令が付いているというところです。
strictとは、初めて変数名が宣言されたとき、頭にmyなどが付いているかをチェックしてくれる命令です。
本当にチェックしてくれているかを知るためには、「my」をはずして動かしてみればわかりますよね。
実際に使ってみるとわかりますが、「use strict;」この1行で、かなり気が楽になりますから、おすすめですよ。
今回の学習はこれで終了です。
ありがとうございました。
<戻る>