Recently in php Category

php と mysqli_ インターフェイス

| No Comments | No TrackBacks

前回にも書きましたけど php 5.3 になっていろいろと変更されたことがあるようで、結構大変です。

嘆いていてもしょうがないので、標準 API の mysqli_* シリーズを使って書き直しているのですが、MDB2 シリーズとの互換性も持ちたいため、かなり難儀しています。

昨今の流れとして、SQL を発行するときはプリペアドステートメントを使うため mysqli_stmt_* シリーズを使って書いているのですが、MDB2 を使用するときと同じインターフェイスにしないと駄目なため class を使って記述をしたい、自作の DB 操作関数群をそういう風に作ったため、なのですが、これが地獄の始まり…

なお、基本的に mysqli_ シリーズの関数は手続き型ではなくオブジェクト指向型を使っています。

  1. SQL を発行するとき
    まぁ、mysqli_stmt_bind_paramを使用するわけですが、mysqli_stmt::bind_param の第二引数以降は参照渡しで定義されています。で、汎用的な class を作っているため、この引数は可変です。私の場合、渡された引数を array 型で構築して、そのまま関数に渡せばいいや。と思ってそのように書いて、call_user_method_arrayという関数を使用することにしました。そしてこの関数は、リファレンスマニュアルにあるとおり、非推奨になっており、call_user_func_arrayを使うことになります。
    ここまでは割と問題なくかけるのですが…以下のように書いたら動かない。警告が出て失敗してしまう。で、まず、これでかなり悩んだのですが…
    $db = new mysqli( IP, USERNAME, PASSWORD, DBNAME );
    $s = '';
    $t = array();
    foreach ( $params as $p ) {
      if ( is_bool($p) or is_int($p) ) {
        $s .= 'i';
        $t[] = $p;
      } elseif ( is_float($p) ) {
        $s .= 'd';
        $t[] = $p;
      } elseif ( is_string($p) ) {
        $s .= 's';
        $t[] = $p;
      } else {
        //  blob 型はまだ
        $s .= 'b';
      }
    }
    $stmt = $db->stmt_init();
    if ($stmt->prepare($query)) {
      call_user_func_array(array($stmt,'bind_param'),array_unshift($t, $s));
      $stmt->execute();
    }
    
    結論。bind_param の2番目以降の引数は参照渡しにしないと駄目。具体的には、foreach で配列を作っているときに参照渡しにする感じ?なんだろうけど…受け取る訳じゃないのに参照渡しって変だよなぁ。
  2. 値を受け取るとき
    まぁ、mysqli_stmt_bind_resultを使うわけですが…これも同じように参照渡し&可変引数なわけで……これかなり悩みました。検索しても大してヒットしないし。で、やっとたどり着いたのが海外の掲示板。要は $$ を二つ重ねて、変数を動的に作る…のかな?初めて見た構文だ(^^ゞ
    で、結果を連想配列で受け取りたかったので以下のように記述
    $rslt = $stmt->result_metadata();
    $header = array();
    while ($field = $rslt->fetch_field()) {
      $key = strtolower($field->name);
      $header[] = $key;
    }
    $data = array();
    foreach ($header as $key) {
      $$key = NULL;
      $data[$key] = &$$key;
    }
    call_user_func_array(array($stmt,'bind_result'), $data);
    
    これで何とか動作…しているといいな。

しかし php 関連の検索ってノイズ乗りすぎでひどいな…あと、php 5.3 になっていろいろ関数仕様が変更されて大変みたい?

php と MDB2 と mysqli

| No Comments | No TrackBacks

割と最近困った出来事。

php のプログラムを書いたとき、データベースを操作するのに pear の MDB2::mysqli インターフェイスを使ったのですよ。

で、そのプログラムを書いたのが数年前。
んで、今になってメンテナンスをする必要が出てきて実行してみたら…

動かない

焦ってソースを追いかけてみたら…どうやら mysqli での操作の結果が失敗している模様。
もう、ね、かなり焦りましたよ。結局 MDB2 側のソースまで追いかけて判明したのが…

php 5.3 で MDB2::mysqli は動かない

という、衝撃の事実。いろいろと検索してみても日本語の情報が全く情報が出てこなくて、やっと見つけたのが pear のバグトラック

どうやら php 5.3 で call_user_func_array の仕様が変更されたのが原因らしい。

なんてこったい…メンテナンスを楽にしようと思って pear インターフェイスを使ったら、それに苦しめられるとはなんという皮肉。

しかし、これ、誰も困っている人いないんかな?それとも mysqli_* API を使うようにするのが普通なんだろうか?それだと DB が変わったときの変更がめんどいしなぁ。

かなり困った問題だ。

php失敗談その1

| No Comments | No TrackBacks

何気なくウェブを見ていたら、各言語におけるtrue/falseまとめというページがあったので、眺めていたら

PHP は複雑。以下のものが偽となり、これら以外はすべて真となる。
<snip>
空の文字列、 および文字列の "0"

…これにはめっちゃはまりましたよ!原因がわからず半日くらい悩んだかなぁ。

if ( $hoge == false ) { }

と書いていたのがさらに混迷を深めてしまって…結局 '0' も偽になることに気づいて、php には === という演算子があることに気づいてなんとか修正できましたけど、このときはかなり冷や汗をかいたなぁ。

ところで、php とは関係ないのですが

意見が分かれそうなところですが、個人的にはNULLを偽値として使用するは好きじゃないです。

私は未だに C/C++ における以下の表記になれることが出来ません(^^ゞ

if ( !strcmp( 文字列変数, "比較文字列" ) ) {/*文字列が等しい時の処理*/}

なんか見るたびにうずうずとしたものが(笑)