生 DBI ユーザーのための DBI Cookbook (2)
さて、まさか続編書くと思わなかったけど、d:id:ZIGOROu:20090731:1249050735 の続きです。
追記 (2009-08-15T00:30:56+09:00)
ちなみに、下記で紹介してる方法は一般的には DBI の資産がたくさん合ってモゴモゴな状況をどうするか…みたいな状況の人向けです。
一般的には宜しくないです、と言うことを踏まえてどうぞ。
DBI の拡張をサブクラスを用いて行う
Subclassing the DBI にちゃんと書いてあるんですが、DBI はサブクラスを作る為の環境が整っています。
論より証拠、実際の例です。
#!/usr/bin/perl use strict; use warnings; use DBI; use YAML; { package DBIx::Hideki; use base qw(DBI); package DBIx::Hideki::db; use base qw(DBI::db); package DBIx::Hideki::st; use base qw(DBI::st); use Time::HiRes qw(time); sub execute { my ($self, @bind_params) = @_; my $start = time(); my $rv = $self->SUPER::execute(@bind_params); my $elapse = time() - $start; print STDERR sprintf('[Hideki Kimura] sql: %s, elapse: %f', $self->{Statement}, $elapse); return $rv; } } my $dbh = DBI->connect('dbi:mysql:dbname=test', 'root', '', +{ RootClass => 'DBIx::Hideki' }); my $sth = $dbh->prepare('SHOW TABLES'); $sth->execute; print Dump($sth->fetchall_arrayref(+{})); $sth->finish; $dbh->disconnect;
これを実行すると、
[Hideki Kimura] sql: SHOW TABLES, elapse: 0.000498--- []
素晴らしいですね。
解説
DBIx::Hideki クラスは DBI を継承してますから、
DBIx::Hideki->connect();
みたいなのは当然動くんですが、いちいち書き換えたくないですよね。その場合には connect 時のオプションで RootClass を指定すると、DBI 側が良しなにサブクラス化してくれます。*1
このようにするとソース自体の書き換えは、接続時のパラメータのみいじれば良く、設定ファイルなんかに書いてある場合はちょっと書き換えるだけで色んな拡張が出来ますね。
注意する点としては、
をそれぞれ継承したモジュールを作らないと駄目って所です。
それと connect 系のメソッドですが、connect 時に RootClass の解決をするため connect 自体を差し替える事は出来ません。
但し connect 後であれば、connected と言うメソッドをコールする事になっているので、
package DBIx::Hideki::db; use base qw(DBI::db); use YAML; sub connected { my ($self, $dsn, $user, $credential, $attrs) = @_; print STDERR "[Hideki Kimura] connected\n"; print STDERR Dump(+{ dsn => $dsn, user => $user, credential => $credential, attrs => $attrs, }); }
みたいな感じで接続直後のデータを受け取りホゲホゲする事が出来ます。
まとめ
今さっき、性質の悪い酔っ払い共から電話が掛かってきました!w
自宅に居るって言ったら「KY」呼ばわりされました。ひどい!
*1: bless しなおしてるだけですが