Perlは奥が深いんだか、浅いんだか、よくわからない言語なのですが、オブジェクトに関してはものすごくPerlらしい振る舞いをするのでちょっと紹介します。というのも、今回仕事で某株式会社のシステムをいじることになったのですが、そのWebサイトっていうのが全部PerlでHTMLをパブリッシングしているんですね。しかもOSがRedhad3で、尚且つmod_perlで動いているわけです。さすがに同じ環境を作れないので、その動作確認が開発元でできないという始末です。しかも10年前以上にライブドアのかなり優秀な方が作ったプログラムなのですが、中身は非常に優秀なのですが、ドキュメントが残っていないという悲しいことになっています。
というわけで、ちょっとPerlを思い出したので書いてみたいと思います。
一部を書いてみると、
sub test2() {}と書きたいところなのですが、Perlは配列の@_に渡されているという約束になっているので、パラメーターを受けるなんらかの記述が必要がないというわけです。ですので、
引数は配列と決まっているので、配列をそのまま渡すことも可能です。&test2(@para);のように渡してもいいし、&test2("テスト4-1","テスト4-2","テスト4-3");みたいに渡してもいいです。ハッシュも問題なく渡ります。
では、返り値を配列とかハッシュにする場合はどうかというと、そのままreturn値に渡してやればいいです。
もう一つの特徴は、サブルーチンを呼び出す際には、&マークをつけて呼び出すということです。これは省略も可能ですが、Perlの特徴として、
ですので、サブルーチンを実際に使う際には、
&test2();というような書き方になります。
コードはこんな風になります。
C言語なんかは変数は全部ローカル扱いになるのが基本です。しかしPerlは何もしないと全部グローバルになります。しかしサブルーチン内で使われている変数はその中ではローカルという扱いになるんですね。
パッケージ(名前空間の区分け)の実際の方法ですが、名前空間内を中括弧{}で囲ってあげます。それからその中で、
それらをどう扱うかというと、::で区切って扱います。
上記の場合だと、
英語でも数学でも馬鹿な連中は「こんなもん使わねーよ。実際は。」というけど、結構使います。使わないけどCPANからもってきたモジュールは殆どこれでできているので、読めないとつらいですよ。
また、パッケージはサブルーチンがいっぱいある場合には、機能別にある名前空間で仕切っておくと便利ですよ。
パッケージの中括弧{}の話ですが、実際問題としてパッケージはかなりのボリュームのあるサブルーチン群をまとめて名前空間に属させることを目的にしています。つまり、別ファイルから呼び出すサブルーチン群を使うという場合が殆どなので、それらのコードを見てみると中括弧なんてないんですね。つまり、ひとつのファイルにまとめてひとつの名前空間をつくる場合は中括弧が必要ないのです。
package test_pachage1; #←名前空間の宣言
sub subtest {
$test = "mogemoge\n";
print $test;
}
return 1;
約束として最後にreturn 1;あるいはただ単に1;というふうにして、終わらせます。
こういったファイルは、requireとかで、呼び出して使うことができます。
というわけで、ちょっとPerlを思い出したので書いてみたいと思います。
サブルーチンの話
Perlのサブルーチンは全部配列で渡すことに決まっています。スカラーで渡せません。スカラーで渡したかったら配列の最初、つまり$xxx[0]みたいな感じで受け取ってくださいというルールになっています。渡すときは、コンマで区切って単品のスカラー変数を渡すことはできますが、受け取る際には全部配列。これが決定的に他の言語と違う部分です。非常に便利なのですが、その他の言語にこういう形がないのでちょっと慣れないという感じです。一部を書いてみると、
# パラメーターのあるのサーブルーチン
sub test2 {
($test2) = @_; #ココ
print $test2." OK<br />\n";
}
# パラメーターと返り値のあるサーブルーチン
sub test3 {
($test3) = @_; #ココ
print $test3." OK<br />\n";
return "OK<br />\n";
}
sub test2() {}と書きたいところなのですが、Perlは配列の@_に渡されているという約束になっているので、パラメーターを受けるなんらかの記述が必要がないというわけです。ですので、
sub test2 {というようにいきなり@_をうけて、いわゆるlist()みたいな感じで配列をスプリットして使いやすいようにスカラー変数に代入してしまいます。(通常みんなこんな風にやります。)もちろん、foreachとかで回してやってもいいです。
($test2) = @_; #ココ
...
引数は配列と決まっているので、配列をそのまま渡すことも可能です。&test2(@para);のように渡してもいいし、&test2("テスト4-1","テスト4-2","テスト4-3");みたいに渡してもいいです。ハッシュも問題なく渡ります。
では、返り値を配列とかハッシュにする場合はどうかというと、そのままreturn値に渡してやればいいです。
もう一つの特徴は、サブルーチンを呼び出す際には、&マークをつけて呼び出すということです。これは省略も可能ですが、Perlの特徴として、
- $ スカラー変数
- @ 配列
- % ハッシュ(連想配列)
- & サブルーチン(ユーザー定義関数?)
ですので、サブルーチンを実際に使う際には、
&test2();というような書き方になります。
ハッシュの話
Perlのhashもこれまたちょっと曲者です。ハッシュというだけあって、その展開の序列はランダムなのです。展開する際には、keysとvaluesを上手に使わないと展開できません。というのもハッシュのキーと値を展開するためにはハッシュのキーと値を分離して取得しなければならないということなんです。@para_key = keys(%hash);ということになります。なので、
@para_value = keys(%hash);
foreach $key ( keys (%hash) ) {ということになります。ますハッシュのkeyを取り出して、そのkeyでもってハッシュから値をひとつひとつ取り出しているわけです。
print "key:$key : value:$hash{$key}", "<br />\n";
}
foreach ($para as $key=>$val) {というようなphpの書き方とはちょっと異なるんです。
print "$key=>$val\n";
}
コードはこんな風になります。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "普通のサブルーチン:";
&test1();
print "パラメーターのあるサブルーチン:";
&test2("テスト2");
print "パラメーターと返り値のあるサーブルーチン:";
$re = &test3("テスト3");
print $re;
print "パラメーター(配列)と返り値のあるサーブルーチン4:";
$re = &test4("テスト4-1","テスト4-2","テスト4-3");
print $re;
print "パラメーター(配列)と返り値のあるサーブルーチン4:";
@para = ("テスト4-1","テスト4-2","テスト4-3");
$re = &test4(@para);
print $re;
print "パラメーター(ハッシュ)と返り値のあるサーブルーチン5:";
%para = ("テスト5-1"=>'5-1',"テスト5-2"=>'5-2',"テスト5-3"=>'5-3');
$re = &test5(%para);
print $re;
print "返り値が配列とかハッシュのサーブルーチン6:";
%para = ("テスト6-1"=>'6-1',"テスト6-2"=>'6-2',"テスト6-3"=>'6-3');
%re = &test6(%para);
foreach $key ( keys (%re) ) {
print "key:$key : value:$hash{$key}", "<br />\n";
}
# 普通のサーブルーチン
sub test1 {
print "test1 OK<br />\n";
}
# パラメーターのあるのサーブルーチン
sub test2 {
($test2) = @_;
print $test2." OK<br />\n";
}
# パラメーターと返り値のあるサーブルーチン
sub test3 {
($test3) = @_;
print $test3." OK<br />\n";
return "OK<br />\n";
}
# パラメーター(配列)と返り値のあるサーブルーチン
sub test4 {
foreach (@_) {
print $_."<br />\n"
}
return "OK<br />\n";
}
# パラメーター(ハッシュ)と返り値のあるサーブルーチン
sub test5 {
%hash = @_;
foreach $key ( keys (%hash) ) {
print "key:$key : value:$hash{$key}", "<br />\n";
}
return "OK<br />\n";
}
# パラメーター(ハッシュ)と返り値のあるサーブルーチン
sub test6 {
%hash = @_;
return %hash;
}
exit;
パッケージの話
さて前回のサブルーチンの話を受けて、今回はパッケージの話をします。この話は名前空間というちょっとややこしい話を交えての話になります。C言語なんかは変数は全部ローカル扱いになるのが基本です。しかしPerlは何もしないと全部グローバルになります。しかしサブルーチン内で使われている変数はその中ではローカルという扱いになるんですね。
$test = "hogehoge\n";$testは、同じ値を受け取っても場所によってグローバルとローカルの区別がなされているので、別々の値を保持してくれます。こんな感じでそれぞれの変数値(もちろんサブルーチン名も含めて)は、名前空間によって保持されるわけです。その構造はディレクトリ構造とかと同じです。
print $test;
&subtest;
sub subtest {
$test = "mogemoge\n";
print $test;
}
名前空間の話
$test = "hogehoge\n";こんな風にやるとsubtestがたぶってしまうのでダメなのです。しかし呼び出すサブルーチンがものすごいたくさんある場合には、もしかしたら名前が被ってしまうこともあるかもわかりません。プロジェクトが大きくなるとそれなりに危険度は増してゆきます。そういう時にはパッケージを使って名前空間を作ってあげます。
print $test;
&subtest;
sub subtest {
$test = "mogemoge\n";
print $test;
}
sub subtest {
$test = "kokekoke\n";
print $test;
}
package main;ここには$testという変数が3つ出てきます。これらは同じ変数名ですが、名前空間を別々にしてあります。通常$testと書いた際には、これはグローバル変数になりメインのスクリプト内で常識的な振る舞いをしてくれます。しかし実はこの$testも暗黙のうちに名前空間を与えられています。この変数は、package mainで宣言されたものと暗黙のうちに了解されているわけです。上記では明示的にpackage main;の宣言をしてみましたが、実のところ必要なしです。わかりづらい場合は書いてあげるということにしておけばいいと思います。
$test = "hogehoge\n";
print $test; #ここはmainパッケージです。
&test_pachage1::subtest;
&test_pachage2::subtest;
{ #←名前空間の最初
package test_pachage1; #←名前空間の宣言
sub subtest {
$test = "mogemoge\n";
print $test;
}
} #←名前空間の終わり
{
package test_pachage2;
sub subtest {
$test = "kokekoke\n";
print $test;
}
}
パッケージ(名前空間の区分け)の実際の方法ですが、名前空間内を中括弧{}で囲ってあげます。それからその中で、
package test_pachage1;と宣言してやればいいんです。これだけで、その中括弧内は、test_package1という名前空間のものとして捉えられ、そのパッケージのノード以下の変数ということになります。
それらをどう扱うかというと、::で区切って扱います。
<パッケージ名>::<変数名、またはサブルーチン名など>;となります。
上記の場合だと、
$main:test; が hogehogeになります。しかしこれは便利です。
&test_pachage1::subtest; が mogemoge
英語でも数学でも馬鹿な連中は「こんなもん使わねーよ。実際は。」というけど、結構使います。使わないけどCPANからもってきたモジュールは殆どこれでできているので、読めないとつらいですよ。
また、パッケージはサブルーチンがいっぱいある場合には、機能別にある名前空間で仕切っておくと便利ですよ。
パッケージの中括弧{}の話ですが、実際問題としてパッケージはかなりのボリュームのあるサブルーチン群をまとめて名前空間に属させることを目的にしています。つまり、別ファイルから呼び出すサブルーチン群を使うという場合が殆どなので、それらのコードを見てみると中括弧なんてないんですね。つまり、ひとつのファイルにまとめてひとつの名前空間をつくる場合は中括弧が必要ないのです。
package test_pachage1; #←名前空間の宣言
sub subtest {
$test = "mogemoge\n";
print $test;
}
return 1;
約束として最後にreturn 1;あるいはただ単に1;というふうにして、終わらせます。
こういったファイルは、requireとかで、呼び出して使うことができます。



