前回、DBへのアクセスに成功した・・・!
しかし接続文字列を処理記述部分に直接書くのはいくらなんでも無いので部品として切り出す。
その前に・・・
ディレクトリの構成もちょっときれいにすることを考える。
cgi-bin
│ (メインプログラム)testDBI.cgi
│
└─CMN
│ (設定ファイル).xml
│
└─DCMN
(データベース共通部品)DCMN.cgi
↑こういう風にしたい。
早速実践する。
接続文字列をXMLファイルから読み込むところは一旦置いておいて、
まずはconnectの切り出しだけをする。
#!"C:\Perl64\bin\perl.exe"
package DCMN;
use DBI;
sub DCMN_connect{
$dbh = DBI->connect('DBI:mysql:sato:127.0.0.1:3306','sato','sato');
return $dbh;
}
1;
これからはDB関連共通部品はDCMN.cgiにまとめておこう。
これをDCMNパッケージとする!
ちなみに末尾の1;は規約みたいなものらしい。
これでインタプリタにプログラムの正常終了を知らせるとのこと。
・・・0じゃないんだ。
んで呼び出し元のtestDBIはこうする。
#!"C:\Perl64\bin\perl.exe"
use CGI::Carp qw(fatalsToBrowser);
require './CMN/DCMN/DCMN.cgi';
$dbh = DCMN::DCMN_connect() or die "$!";
$sql = "SELECT "
. "user_name "
."FROM "
. "sato.test_user_tb "
."ORDER BY "
. "user_id";
print "Content-Type: text/html; charset=UTF-8\n\n";
print '<html>';
print '<head>';
print '<meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS">';
print '<title>TEST</title>';
print '</head>';
print '<body>';
$result = $dbh->selectall_arrayref($sql);
foreach $data(@{$result}){
print '<br>';
print $data->[$i];
}
$dbh->disconnect;
print '</body>';
print '</html>';
今まで頭にあった
use DBI;
は読み込んだ共通部品がやるから必要がなく、消した。
そして、
require './CMN/DCMN/DCMN.cgi';
でカレントディレクトリから共通部品のファイルの場所を指定する。
記事の下のほうにも書いてあるが、カレントディレクトリといっても実行中のプログラムソースの場所とは関係ないのに注意。
その次の
$dbh = DCMN::DCMN_connect() or die "$!";
で、DCMNパッケージ内のDCMN_connect()メソッドを呼び出してコネクションを受け取る。
ところでなんで
$dbh = DCMN->DCMN_connect() or die "$!";
じゃないんだろう?
静的なメソッドとして認識してるのか・・・?
そんなこんなで結果を受け取る。
ここでもっと別の書き方を模索する。
perlは多重継承が可能なので次のような妄想をする。
「たくさん便利な共通部品を作って、それらを継承したプログラムを基盤にしたら・・・
最強じゃないのか??!!」
というわけで冒頭で継承を使って書くとこうなる。
#!"C:\Perl64\bin\perl.exe"
use lib './CMN/DCMN';
use base 'CMN::DCMN::DCMN';
$dbh = CMN::DCMN::DCMN->DCMN_connect() or die "$!";
~~~html出力部分はもう書かんでもええやろ?~~~
まず、
use base 'CMN::DCMN::DCMN';
で継承する。
継承したらそのクラスのメソッドが使えるので
$dbh = CMN::DCMN::DCMN->DCMN_connect() or die "$!";
となる。
ただし、同一ファイル内じゃなくて外部ファイルでしかも別ディレクトリにしてるから
use lib './CMN/DCMN';
が要る。
何をしているかというと、これで@ISAという特殊変数にモジュールの場所を追記している。
ちょうど、Windowsではパスを設定しないと.exe等を探しにいけないのと同様に、
perlでは@ISAにパスを設定しないと.pm(モジュールファイル)を探しにいけないのである。
そしてこれを実行すると・・・・エラーになる。
ここからは単なる外部ファイルではなく、モジュールとして扱わなければならない。
ということで
DCMN.cgi改めDCMN.pmを作成する。
#!"C:\Perl64\bin\perl.exe"
package CMN::DCMN::DCMN;
use DBI;
sub DCMN_connect{
$dbh = DBI->connect('DBI:mysql:sato:127.0.0.1:3306','sato','sato');
return $dbh;
}
1;
パッケージ宣言が
package DCMN;
ではなく
package CMN::DCMN::DCMN;
とかなっているのは、カレントディレクトリはソースのディレクトリと関係ないから。
めんどくせえ仕様の言語である。
継承はできたが・・・やっぱり多重継承というC++の過ちを繰り返さないためにも
(それでJavaは継承元が1つのみだし、Javaのパクリのvb.netもそうだし、
今仕事で使ってるフレームワークはコーディング規約で継承禁止にされている。)
共通部品以外での継承は原則禁止とする俺規約を定める。
そういうわけでクラスのインスタンス化という一般的な方法をとる。
最初からなぜこうしなかったのか・・・
#!"C:\Perl64\bin\perl.exe"
use lib './CMN/DCMN';
use CMN::DCMN::DCMN;
my $dcmn = CMN::DCMN::DCMN->new();
$dbh = $dcmn->DCMN_connect() or die "$!";
~~~html出力部分はもう書かんでもええやろ?~~~
Javaや.netでなじみのあるnew()の登場する書き方になった。
だいぶ理解し易い。
同時に、DCMN.pmにもインスタンスを返すnewメソッドを追加する。
perlではどうやら、デフォルトコンストラクタも自分で書かなければいけないらしい。
#!"C:\Perl64\bin\perl.exe"
package CMN::DCMN::DCMN;
use DBI;
sub new {
return bless {} ;
}
sub DCMN_connect{
$dbh = DBI->connect('DBI:mysql:sato:127.0.0.1:3306','sato','sato');
return $dbh;
}
1;
これでうまくいきました。
なんとなくDLLのようになったが、
そもそもスクリプト言語で動的リンクとか静的リンクとか区別する必要があるのか疑わしい。
まあ、厳密な話はなしにしようや。
さて、次は接続文字列をXMLに切り出し、そこから読み込む部品を作るとする。
・・・・これが地獄であった

