第8回 保存先の変更 その2 - OOP講座

PHPセキュリティ

がる先生のOOP講座

Lecutures on PHP

第8回 保存先の変更 その2 (その1)

 このエントリーをはてなブックマークに追加

保存先の変更 その2

がる先生DBの使い方が何となくわかったところで実装に入…る前に。
まずは「テーブル」をざっくりと切っていきましょう。

筆者の個人的感想ですが。テーブルを切るのとクラスを切るのには、非常に似たようなところがあります。
クラスが「1インスタンスの意味」に対して厳密に切るのと同様に、テーブルは「1レコードの意味」をしっかりと念頭に置いておくと、比較的きれいに切れるように思います。

今回切る唯一にしてメインのテーブルは、当然ながら「1レコード == 1つの発言」になります。
具体的なテーブルレイアウトは後ほど考えるとして、まずは「1レコードが1発言を意味するテーブルがある」事を念頭に、一端先に進めてみましょう。

まずは相変わらずのざっくりした「日本語ソースコード」です。
readとwriteについてそれぞれ確認をしてみましょう。

list 1

readの処理

  1    // 表示したい発言のnoを取得する
  2    // DBにconnect、DBハンドルを取得する
  3    // 必要なSQL文を作成する
  4    // SQL文を発行する
  5    // データを読み取る
  6    // 出力する(テンプレートエンジンに変数を設定する)
  7    // DBハンドルをcloseする
list 2

writeの処理

  1    // 入力されたデータを取得する
  2    // DBにconnect、DBハンドルを取得する
  3    // 必要なSQL文を作成する
  4    // SQL文を発行する
  5    // DBハンドルをcloseする

当然といえば当然なのですが。DBに関連する処理ですから、なんか明らかに「コピペしただろ」ってくらいに似ている(クリソツ、という単語は死語なんでしょうか?)部分がありますので切り出していきましょう。
何よりも似ているのがここです。

list 3
  1    // DBにconnect、DBハンドルを取得する
  2    // DBハンドルをcloseする

開けて閉める。通信用のsocketからファイルから、このあたりのお作法にはなんも変化はありませんので、DBでも同様のお作法でございます。
同じお作法というからには「プロセスが終了したらOSが自動で閉じてくれる」ってのもまたもちろん同様だったりはするのですが、そのあたりは「丁寧に」いきましょう。FCGIとか使ってる時に下手にCloseされると困るのですが、それはまた別のお話。

ではDBハンドルを開けます………さて、今回のシステムはMySQLだったでしょうか? PostgreSQLだったでしょうか?
OracleやDB2とは想像しにくいのですし、sybaseだったりFirebirdもしないとは思うのですが、、こういう時に悩んでわかるのは予言者くらいなもんです。
悩む前に、とっとと決定権を持っている上司にお伺いを立てましょう。というわけで速やかに質問mailを送ります。

.....
...

返事が返ってきました。どれどれ…

<<メール>>
まだ協議中だから、どれになっても問題ないようにしてくれ。

がる先生どーしたもんでしょうかねぇ。とりあえず、砥石で鉈でも研ぎましょうか? 完全な計画のほうが先ですかねぇ?
………とかいう本音は一端棚の上に上げておきまして。

いやまぁあんまり冗談でもなく。RDBのプロダクトが不安定になる瞬間というのは、時々存在します。時々です、高頻度ではありません。
とはいえ…納品一週間前くらいのタイミングで「あっさりとプロダクトの変更をされた」経験が筆者にもございますしねぇ。…こういうのを「あんまり知りたくない世界」とか言ったり言わなかったり。。

まじめなところに話を戻しまして。
「RDBのプロダクトに固有な処理」をあんまり孕んでしまうと後々面倒だったりもするので、ここはよいチャンスだと思って「ある程度汎用的な書き方」を模索していきましょう。

とはいえ、PHPのマニュアルで接続する関数を調べても…困ったくらいに多種多様です、っていうかプロダクト毎にバランバランです。
とりあえず、ざっくりとDBとのconnectを行う関数を列挙してみましょう。

sybase_connect (http://www.phppro.jp/phpmanual/php/function.sybase-connect.html
resource sybase_connect ([ string $servername [, string $username [, string $password [, string $charset [, string $appname [, bool $new = false ]]]]]] )


ibase_connect (http://www.phppro.jp/phpmanual/php/function.ibase-connect.html
resource ibase_connect ([ string $database [, string $username [, string $password [, string $charset [, int $buffers [, int $dialect [, string $role [, int $sync ]]]]]]]] )


db2_connect (http://www.phppro.jp/phpmanual/php/function.db2-connect.html
resource db2_connect ( string $database , string $username , string $password [, array $options ] )


mysql_connect (http://www.phppro.jp/phpmanual/php/function.mysql-connect.html
resource mysql_connect ([ string $server = ini_get("mysql.default_host") [, string $username = ini_get("mysql.default_user") [, string $password = ini_get("mysql.default_password") [, bool $new_link = false [, int $client_flags = 0 ]]]]] )


mysqli::__construct (http://www.phppro.jp/phpmanual/php/mysqli.connect.html
mysqli::__construct ([ string $host = ini_get("mysqli.default_host") [, string $username = ini_get("mysqli.default_user") [, string $passwd = ini_get("mysqli.default_pw") [, string $dbname = "" [, int $port = ini_get("mysqli.default_port") [, string $socket = ini_get("mysqli.default_socket") ]]]]]] )


oci_connect (http://www.phppro.jp/phpmanual/php/function.oci-connect.html
resource oci_connect ( string $username , string $password [, string $connection_string [, string $character_set [, int $session_mode ]]] )


pg_connect (http://www.phppro.jp/phpmanual/php/function.pg-connect.html
resource pg_connect ( string $connection_string [, int $connect_type ] )

…大抵「どんだけ~」ってな種類があります。
こんだけ多種多様だとあきらめる…には少々早すぎるので。もう少しざっくりと見てみます。

全体的に、引数に少し注目をしてみましょう。
そうすると、ふと、ある事に気づきます。
どのDBハンドルを取得するときも、大抵

  • 接続アカウント名
  • パスワード
  • 接続database名
  • 接続ホスト名
  • 接続ポート番号

という引数の群れがあります。
ここで「なんか共通化できるんぢゃね?」と発想するのがエンジニアってぇもんです。

えと…ちょっと雑に考えてみましょう。
まず、接続用の情報をぶち込むようの「なにか」を用意します。

list 4
  1    $obj = new なにか();
  2    
$obj->set_user_id(接続アカウント名);
  3    
$obj->set_password(パスワード);
  4    
$obj->set_database_name(接続database名);
  5    
$obj->set_host_name(接続ホスト名);
  6    
$obj->set_port_num(接続ポート番号);

そうして、例えばこのobjをつかって、こんな風にDBハンドルを取れたら、なんか楽そうじゃないでしょうか?

list 5
  1    // パラメタつくって
  2    
$obj = new なにか();
  3    
$obj->set_user_id(接続アカウント名);
  4    
$obj->set_password(パスワード);
  5    
$obj->set_database_name(接続database名);
  6    
$obj->set_host_name(接続ホスト名);
  7    
$obj->set_port_num(接続ポート番号);
  8  
  9    
// DBハンドルをもらう
 10    
$dbh DBハンドル作る君::ハンドル作って下さい('MySQL'$obj);

これだと、MySQLがPostgreSQLになろうがFirebirdになろうが、ある程度まで対応ができそうな気がします。
PostgreSQLになったら、多分

list 6
  1    // パラメタつくって
  2    
$obj = new なにか();
  3    
$obj->set_user_id(接続アカウント名);
  4    
$obj->set_password(パスワード);
  5    
$obj->set_database_name(接続database名);
  6    
$obj->set_host_name(接続ホスト名);
  7    
$obj->set_port_num(接続ポート番号);
  8  
  9    
// DBハンドルをもらう
 10    
$dbh DBハンドル作る君::ハンドル作って下さい('PostgreSQL'$obj);

とかで完了です。
しかも、接続情報って大抵、外だしのconfigファイルに書いてありますよね?
だとすると、

list 7
  1    // DBハンドルをもらう
  2    
$dbh DBハンドル作る君::ハンドル作って下さいconfigファイル名 );

がる先生でいけちゃうんんじゃないでしょうか?
っていうかこれでいけると嬉しいですよね?

で、実際問題これでいけちゃうんです。
これは、業界的専門用語で格好よく言うと
「GoFのFactoryパターンを使っている」
と言います。テストに出るからちゃんとメモしておいてください(なんのテストだ)。

  • 1
  • 2


Pick Up Q&A

Q
PHPのHTML埋め込み記述について
 このエントリーをはてなブックマークに追加 
A
$_POST["data"] == "男" ? $val = "checked" : $val = "" ; の意味は以下と同じです。 if($_POST["data"] == "男"){ $val = "checked; } e...

>>続きを読む

kende様のご指摘通り、三項演算子を使用する際には、コードの複雑度などを考慮する必要がありますね。書きやすさと共に可読性も追求したいところですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)