2007年9月28日金曜日

データベースへの追加・更新…どのクラスで実装すべき?

 何を今更…と言う様な話なのは重々承知ですw

 PHP4もライフサイクルが終了しますので、来年を持って会社で開発・使用していたFrameworkも終了し、ZendFrameworkに乗り換え様かと会社のSEさんが言ってました.

 そうだよね.
 と言いますか、ぶっちゃけ乗り換えがかなりの勢いで遅いですw
 しかしそれもPHP4で運用している環境をサポートしなければならなかったが故(ZendFrameworkはPHP5.1.4以降で動作).
 致し方なしと言った所でしょう.

 所で、lightmaterialを含め会社の人はPHP/.Netを使っているんですが、.Netの影響か会社のPHPFrameworkではDBに対するINSERT/UPDATE/DELETEをマネージャで実装しています.
 勿論正確にはDBAdapter(DataBase用のアダプタ)のメソッドを呼び出すのがマネージャな訳です.
 ADO.Netも似た様な構造です.
 fillしたデータの各行に対して変更を加え、それらDBへのコミットはDataAdapterから行いますが、それを呼び出すのは当然マネージャなりデータを操作するクラスだったりします(個別に操作する別の方法もありますが、オブジェクト指向としては醜い方法です…と思いますw).

 が、ZendFrameworkのマニュアルを読むとDataRowクラスに「save」メソッド(追加・更新をDBへ反映させるメソッド)が実装されています.
 要するに

  $objRow = $objTable->createRow();
  $objRow->save();
  //-> 酒飲みながら流し見してたので本当にTableからcreateRowするかは確認してませんが、普通に考えればTableクラスから生成するかと.

 な訳ですよ.
 …いや、確かにそう言う実装方法も色々と見て来ましたので、別に戸惑う事でも何でもないんですが、ふと「あれ?DBへの追加・更新用のメソッドって、どこに実装すべきなんだ?どこに実装するのがエクセレントなんだ?」と言う疑問が湧き上がって訳です.

 実際の所、どちらの方がスマートなんだろう?
 各Rowに対する変更をTableオブジェクトでストアして一気にコミット…大量のデータが変更される環境では、トラフィック効率が非常に魅力的な方法です(リアルタイム性に欠けるんですがw).
 一方、各Rowにsave/deleteメソッドが実装されていると、小回りが効くと言うか、何かしらのインポート処理では無い限り、こちらの方がリアルタイム性+トラフィック効率が良い様な気もします(さっきと書いてる事違うじゃない…と言う事は無く、一度に大量の処理が発生する場合は前者の方がトラフィックが減りますが、1レコードしか更新しない場合には後者のほうがトラフィックは少なくなります).
 ただしこの方法、数万レコードのインポート処理が発生するプログラムの場合、相当処理が遅いんじゃないの? orz

 うーん.
 難しい.
 Javaのデータベース周りって、どっちの方法がスタンダードなんだろ?
 どちらのアプローチも間違いじゃないから悩ましい.
 でもZendFrameworkに乗り換えるのは殆ど決定事項みたいですので、これからは2つのアプローチに慣れる必要がありそうです.

 それにしても、会社のFrameworkってプログラム量が凄い少なくて済む(と言うか、かなりの勢いで全自動)から気に入ってたんですけどねぇ.
 ちょっと残念です.

2007年9月25日火曜日

SafariのLabelエレメント.

 ちょっと仕事中だけど忘れない様にメモ.
 さっさと書きなぐります.

 Macの標準ブラウザであるSafari.
 会社には古いPowerPC系のMacしかないんだけど、そいつに入っているSafari(1.3.x系)ではLabelエレメントに対するJavascriptの取扱がちょっと変(もしかすると、この挙動が正規の動きなのかもしれないけど).

<form name="test_post" method="post">
<label onclick="javascript: alert(this.form.name)">テスト</label>
</form>

 こんな感じで書くと、Formの名前は拾ってくれません(Labelエレメントの「this」そのものが無効. IEやFirefoxは拾います).
 私の中ではこの状態を「Safariの挙動」として把握していたのですが、ふとWindows版のSafariで同じ様なJavaScriptを動かしてみると、正常(?)に動作しやがります.

 …で、結局どの挙動が正常なんだ? orz

 今回はWindows版しか試してませんが、もしかしてIntel Mac用(MacOS X 10.4.x)のSafari(2.0.x)でも普通に動くのか??
 むしろ1.3.x系Safariには、こんな下らないバグがずーっと残ってたとでも言うのか??

 うーん…今現状Intel Macが手元に無いから試しようが無いしなぁ~
 ちらっと検索しても、なかなか該当する記事を見つける事が出来ませんでしたし.
 これを口実に会社でIntel Mac買ってもらうかなw

2007年9月21日金曜日

PDF出力が一対一の直つなぎ環境で出力されなかった問題.

 先日書いた一対一の直つなぎ環境だとPDFが出力されない、と言う問題.
 なんの事は無い、単にサーバー側のDNS設定がおかしかっただけでした orz

 誤設定 → ルータ環境下でのDNS設定のまま
 正設定 → 直つなぎ相手または自分

 …って…んが?
 何でだ?
 そう言うもんなのか?
 DNS設定がおかしいと、HTML/PHPは正常に表示されるが、PDF出力(PHPから生成)の場合は表示されないって?
 そんなバカな話あるのか?

 うーん…と言う事で、やっぱりコードが悪いのかもw

 これは後日要確認!(と書いて調べてない事が山ほどある事は忘却の彼方へ…時間見て遣り残してる確認事項終わらせないとなぁ).

2007年9月18日火曜日

今宵は愚痴を.

 18日22時現在…36時間起きっぱなし、ついさっきまで仕事しっぱなしの状態 orz
 昨日は祝日なのに現時点で36時間…そう、休日仕事からのブチ抜きと言う最悪状態ですw

 いや、自分が悪い部分もあるからある程度仕方ないと思うけど、流石に36時間頭フル回転の状態を続けると心身ともにぐったりです.
 ただ、不思議な事に眠気はさほどありません.
 朝が眠気のピークで、後はダルイだけです.
 しかも余り普段と変わらないダルさ.
 それどころか、さっきシャワーを浴びながら「このまま今日も徹夜で行けるんじゃ?」と思ったから自分が怖い.

 因みに、仕事の山場を過ぎて終焉を迎えようかと言う時に「PDFがインターネットに繋がっている環境だと出力されるが、一対一の直つなぎ等のクローズドなネットワーク環境だと出力されない」と言う意味不明な現象に出くわしましたが、思考回路が焼き付きそうだったので放棄してきました orz
 他のマシンだと問題無いので、たぶんコードじゃなくてネットワークの設定だとは思うんですけど、PDFが出力されないクローズドなネットワークでも普通にページ(スクリプト)の表示は出来るんだよなぁ…何だろ??
 正に意味不明.
 寝てすっきりすれば直ぐ解決と言う楽な話に…はならないか orz

 さ、悩みは明日に回してさっさと寝よ.

2007年9月9日日曜日

PHPの配列によるメモリ消費.

 久々更新.

 前から思っていましたが、何故PHPの配列はあんなにメモリを消費するんだろ.
 大きいデータの場合、文字列→配列へexplodeなりすると、メモリ消費量が一気に10倍程度まで跳ね上がります orz
 この傾向は当然ながらデータサイズが小さい物より大きいものの方がより顕著です.
 迂闊に大きいデータを配列化しようものなら、貴重なメモリ資源が喰い散らかされてしまいます(終了時には解放されますが、Linuxのメモリ最適化処理なんかの環境下だと、終了後も一見掴みっぱなしに見えるから気持ち悪い…).
 例えばデータベース.
 データベース回りの機能をクラス化すると、大抵SELECTクエリの結果データを配列へ格納する様に作ると思いますが、この時も直接mysql_fetch_xxxxで処理を回すより結構なメモリ消費量となってしまいます.
 更に、データベースから取得した配列データのエンコードを変換して出力したいとした時、利便性から「mb_convert_variables」(配列データ中のエンコードを指定のエンコードに一括変換する関数)を使うケースが多いと思いますが、この「mb_convert_variables」も曲者で、処理後のメモリ消費が処理前の倍近くになってしまいます.
 分かり易く書くと↓こんな感じ.

echo "MEMORY0 : " . number_format(memory_get_usage()) . " byte(初期値)<br>";

$strBuffer = str_repeat("ABCDEFG,", 10000);
echo "MEMORY1 : " . number_format(memory_get_usage()) . " byte(文字列生成)<br>";

$aryBuffer = explode(",", $strBuffer);
echo "MEMORY2 : " . number_format(memory_get_usage()) . " byte(配列生成)<br>";

unset($strBuffer);
echo "MEMORY3 : " . number_format(memory_get_usage()) . " byte(文字列解放)<br>";

mb_convert_variables("SJIS-win", "UTF-8", $aryBuffer);
echo "MEMORY4 : " . number_format(memory_get_usage()) . " byte(mb_convert_variables実行)<br>";

unset($aryBuffer);
echo "MEMORY5 : " . number_format(memory_get_usage()) . " byte(配列解放)<br>";

 ※PHP5.2.1以前の場合、「memory_get_usage」は「--enable-memory-limit」付きでメイクする必要があります.

 結果↓

MEMORY0 : 59,160 byte(初期値)
MEMORY1 : 139,568 byte(文字列生成)
MEMORY2 : 1,045,532 byte(配列生成)
MEMORY3 : 965,600 byte(文字列解放)
MEMORY4 : 1,637,344 byte(mb_convert_variables実行)
MEMORY5 : 91,424 byte(配列解放)


 内部で単純に複製して変換しているからなのかもしれませんが、メモリ消費が変換対象の配列変数を解放するまで掴みっぱなしになるのは如何なものかと…

 まぁそんな事言い出すと、全部変数解放した後の消費量も気になるじゃねーか!って話になりますけどw

 こうして考えると、世にあるPHP用Frameworkがそれぞれどの程度のメモリ消費なのか、見比べてみるのも面白いかもしれません.
 同等の機能を実現出来るFrameworkなら、エコなコードの方がいいに決まってますから.