ありがとう。また会おう。

ゆるいかんじで。かたのちからぬいて。やってます。

Smartyを使用するときのMVCのMとC。

連投でSmartyネタ。


今関わってる案件で、クライアント要望でSmarty必須な案件があるんだけど、
Smartyはまぁいいとして、MVCの残り、MとCをどうするか思案中。


Mは条件揃えばなんだけど、Doctrine試してみたい。
Doctrine使ったことないんだけど、サンプルソースを見る限りはPropelよりソースの可読性がいいと思うので。
あと、Propelはスキーマ定義がXMLだったり、Propel1.2で使ってるDB抽象レイヤのCreoleが開発終了だったりするし、Propel1.3はまだβだしってのもあり。


で、Mはもうある意味結論は8割方出てるんだけど、問題はC。
Modelはまぁある程度どんなフレームワークでも融通効くと思うんだけど
ControllerはViewと結構密接だったりしますよね。。。
Smarty前提でうまく組み込めるController、というかフレームワークないかなぁ。。。と思っていろいろ探してみたものの、結局断念。
symfonyは論外(笑)*1
その他cakePHP、CodeIgniter、rhacoEthna、guess framework classic、ちいたんなどいろいろ仕様調べたけど・・・自分が求めてるものと違う。
かろうじて近いかなと思ったのがZendだったけど、これも最終的には蹴り。


何が問題かというと、Smartyが前提で、かつクライアントも納品後にシステムに触る可能性があるんだけど、
そういう前提だと、あんまフレームワークフレームワークしたフレームワークは採用しづらいんですよねぇ。。。
軽量で、かつ、「ベタで公開ディレクトリ以下に置くようなページコントローラ的な感覚で使える」ようなのってないかなぁ、と思ったんですが、そんな変態的なもの(笑)は需要がないですかねぇ。。。


ページコントローラだとどうがんばってもDRY原則に反するソースを書かなければいけないのが悩みどころ。
なので、ページコントローラベースであっても、重複コードを如何に少なくするかを思案しております、はい。。。

*1:Smarty前提でなければありなんだけど

特殊な条件下でAffectedRowsが取得できない

嵌りました。。。orz
かなり特殊な状況ではあるのですが、同じ落とし穴に他の人が嵌らないよう、メモ。


使用しているバージョンは
PHP:5.2.6
PEARMDB2:現時点で最新
PostgreSQL:7.4系


で、問題は、PEARマニュアル
http://pear.php.net/manual/ja/package.database.mdb2.intro-execute.php
にある、「例 39-2execute() に配列を渡す」の要領で

<?php
//なんか適当なINSERT文をprepareしてるとして
$affectedRows = $sth->execute($data);
var_dump($affectedRows);

としても、出力が

int(0)

・・・なぜ!?データベースの中身はちゃんと更新されてるのに!!


で、いろいろ調べてたら、なんか奇妙な事実が次々とでてきた。

  1. DML文はどれを実行しても(INSERT/UPDATE/DELETE)、0が返る。エラーにはならない。データベースもちゃんと更新されている。
  2. プリペアードステートメントを使わず、直接 $sth->exec() した場合はちゃんと取得できる


これはもう挙動を追うしかないなぁ。。。と思い、MDB2のソースを探索。
う〜ん・・・execute()もexec()も最終的に行き着くところ同じなんだ。。。
だとすると、余計この2つで挙動が違うのか理解できない。。。


PostgreSQLがPREPAREをサポートしてないバージョン?
・・・いや、7.4からサポートだから、それは大丈夫なはず。。。
PHPのpg_prepare()関数も、5.1以降だから条件は満たしてるはず。。。


でもなんか妙に気になったので、試しにこのコードを実行してみた:

<?php
var_dump(function_exists('pg_prepare'));

//出力結果
//bool(false)

・・・・はぁ!?.。ooO(゚ぺ/)/


なぜ?なぜ?


PHPPostgreSQLもバージョン条件は満たしてるのに。。。


更に気になったので。。。

<?php
var_dump(function_exists('pg_execute'));
var_dump(function_exists('pg_query_param'));

//出力結果
//bool(true)
//bool(true)

はへっ!?


なんじゃこりゃ。。。わけわからん。。。(x_x)


どうやら、pg_prepare()だけが使えない模様。
う〜ん、これはどうもPHPのコンパイルオプションとか絡んでそうだな。。。
あと、PostgreSQLのライブラリのインクルードがどうとか。。。


ちょっとそっちを追いかけるのは後にしてと。
この、pg_prepare()が使えない、という前提で、もう一度MDB2をコードリーディング。


なるほどね。わかった。
どうやら、MDB2内部ではこんな風になってるらしい。

  1. pg_prepare()関数があれば、それを使う
  2. pg_prepare()がなくて、PostgreSQLがPREPARE構文をサポートするなら、pg_query()でPREPARE構文を使用する
  3. それもだめなら、MDB2でエミュレート

で、問題はこの2番目。
pg_query()関数を使って、PREPARE/EXECUTE構文をSQLとして発行する場合、pg_affected_rows()関数が影響行数を返さないんじゃないか疑惑浮上。
MDB2のexecute()メソッドの返値は、追っかけると最終的にpg_affected_rows()関数を呼び出しているので)


そこで実験。

<?php
$conn = pg_connect(DB_CONN_STRING);//DB_CONN_STRING は正しいDB接続文字列を格納した定数とする。
$sql_prepare = 'PREPARE test_stmt(text) AS INSERT INTO hoge VALUES ($1) ';
pg_query($conn, $sql_prepare);
$sql_execute = "EXECUTE test_stmt('fuga')";
$res = pg_query($conn, $sql_execute);
$affectedRows = pg_affected_rows($res);
var_dump($affectedRows);

出力結果:

int(0)

ビンゴだ。。。


わかったことを整理すると。

  • pg_affected_rows()関数は、PREPARE/EXECUTE構文をpg_query()関数で直接呼び出した場合には、影響行数を返さず、常に0を返す
  • MDB2は、pg_prepare()が使えないと、PREPARE/EXECUTE構文を使おうとする。

これが原因で、AffectedRowsが取得できなかったのか。。。


しかし、「(PHP/PostgreSQLのバージョン条件は満たしてるのに)なぜ pg_prepare()関数が未定義か? 」については未解決。。。
これはもう少し深いところ追いかけないとわからなそうだ。。。orz

PHP5.3から導入される(予定の)、namespaceの区切り文字、続き。

しつこいですが。。。


どうやら、この件、完全にFixってわけでもない。。。
というか、異論というか、こういう場合どうよ!?みたいな意見もでているみたいで。。。
\n とか \t ってPHPのダブルクウォート文字列内で特別な意味もつじゃん、その時どうすんのさ!?みたいなことで。


どういう結論に落ち着くのか、まだなんともってとこですが。。。
ちょっと落ち着いて考えてみました。namespaceの区切り文字候補。
条件としては

  • 既存のシンボルに被らない(必須!)
  • できるだけ見た目わかりやすく
  • 文法的にも誤解のないよう
  • できればタイピングしやすい

ってとこでしょうか。

PHPってもう結構いろんなシンボル使ってるから、空きがないってのが正直なところなんでしょうが。。。例えば。。。


2連ピリオド【 .. 】とか


3連ハイフン【 --- 】とか、どうですかね?


ほか、@@ とか、!! とか、%% とか、;; とかいろいろ考えたんですが、どれも見た目的にイマイチなんですよね。。。てか読みにくすぎ。。。
この問題、あまり拙速な結論を出さず、充分議論してほしいなぁ、と思ったりしてます、はい。

PHP5.3から導入される、namespaceの区切り文字。

The result is that we have decided to go with backslash as new separator for namespaces.


え〜〜!?まじっすか。。。orz
またしても、(Perl|Ruby|Python|JavaScript)な人たちにdisられそうだなぁ。。。
そら、確かに空いてる記号があんまないのはわかるけどさぁ。。。


これって、例えば今のPEARパッケージでそれっぽく書けば

<?php
namespace HTTP\Request;

ってことだよね!?
激しく読みづらいだろ。。。orz*1


あと、この文字に決まった、ってみた瞬間、心配したのが、いわゆる「0x5c」問題。
Shift_JISPHPスクリプト書いてたらなんかやばいんじゃないか!?
・・・って考えたんですが・・・これは多分大丈夫・・・かな?
文法上0x5cが問題になるのは、文字列リテラルの中にある時だからね。
PHPプログラムの構文内に出てくる限りは・・・大丈夫・・・かな・・・?
ちょっと自信は無いけど。

*1:ああ、英語圏の人はバックスラッシュだからまだ読みやすいのかなぁ。。。

switchの挙動

via:PHPの種 ブログ » PHP の switch 文は判定が緩やか
PHP の switch 文は怖くて使えない - れぶろぐ (2008-10-02)

これもキモいところですねぇ。。。知ってたけど。
だから僕はswitchで判定する変数に何が入るかわからんような場合は、switchを使わないか、

<?php
switch (true){
case ($value === 'abc'):
 :
case ($value === 'def'):
 :
default:
 :
}

って書きますねぇ。ま、この書き方だとif〜else ifと大差ないやん!というツッコミはごもっとも。


嫌らしいと言えば嫌らしいですよねぇ。。。
厳格な判定をするswitch構文とか、作ってくれないですかねぇ。
Strict Switch だから sswitch とか(爆)

array_shift()の挙動

PHPの組み込み関数の変な挙動 - XOOPS専門-株式会社RYUS

あ〜・・・言われてみれば、変と言えば変か。。。
ようは、PHPって添字配列と連想配列(ハッシュ)を区別しないからこういうことおきるんよね。
array_popとかarray_shiftは本来添字配列を対象にしたものでしょう。
(そもそも連想配列で、pop/shiftみたいな「最初の要素」「最後の要素」って考え方おかしいし)


てことで、そこもまぁPHPのキモいとこだけど、利用者側が理解して使うしかないんだろうね。。。