Unknown::Programming このページをアンテナに追加 RSSフィード

2011-12-18 不逞

MDB2で複数のDB接続を行う場合の恐ろしい罠

MDB2を使って複数のDB接続したいなんてことあるよね。

ところがどっこい、実際にコードを書いてみると恐ろしいことが起きた。それは二つ目のDB接続をすると一つ目のDB接続が二つ目のDB接続に乗っ取られてしまうという!

<?php
// fooというデータベースへ接続し、hoge_tblのカウントする
$dbh = MDB2::factory('mysql://user:pass@localhost/foo?charset=utf8');
$res = $dbh->query('SELECT COUNT(*) FROM hoge_tbl');
$row = $res->fetchRow();
$res->free();
print $row[0]; // 5件

// で次にbarへ接続し同様の処理
$dbh2 = MDB2::factory('mysql://user:pass@localhost/bar?charset=utf8');
$res = $dbh2->query('SELECT COUNT(*) FROM hoge_tbl');
$row = $res->fetchRow();
$res->free();
print $row[0]; // 2件

// そして、fooに接続してるDBハンドルでもういちどカウントしてみると・・・
$res = $dbh->query('SELECT COUNT(*) FROM hoge_tbl');
$row = $res->fetchRow();
$res->free();
print $row[0]; // 2件

このコードが5、2、2と表示されるわけです。なんでこんなことに・・・、と思って色々調べてみると、どうやら同一ホストへの接続の場合、いろいろキャッシュ的な感じでごにょごにょむにょむにょして同一の接続扱いになってしまうようです。

でまぁ原因はわかったけど、じゃあどうやって複数接続すればいいんだよ!ということで、これを明示的に別の接続として扱うためのnew_linkってオプションを発見。

<?php
// new_link=trueをつけましょう!
$dbh2 = MDB2::factory('mysql://user:pass@localhost/bar?charset=utf8&new_link=true');

こうすることで二つ目のDB接続は新しい接続だよ!と明示され、晴れて同一の接続じゃなくなりました。

いやぁnew_linkなんていう便利なオプションがあるんですね() # デフォでtrueにしとけよ!って感じですが。

ということで今頃気付いたのかよって思う人もいるかもしれませんが、知らなかった人はもしかしたら気付かない間に別のDBに接続されててバグだらけになってた、なんてことになってるかもしれないのでご愁傷様です。

2011-06-16 脱却

クラス内で定義した定数の一覧を得る方法

<?php

class Foo {
    const BAR = 1;
    const BAZ = 2;
}

get_defined_constantsを使えば全ての定数が取れると思いきや、上記のようなクラス内で定義した定数は取れなかった。

どうやったら取れるのか。PHPお得意の大量の関数の中に一覧取れるヤツが必ずあるはず!と思いきや、なかった。

諦めかけたその時、ReflectionClassというクラスを使えば取れることがわかったのだ!

<?php

class Foo {
    const BAR = 1;
    const BAZ = 2;
}
$reflect = new ReflectionClass('Foo');
print_r( $reflect->getConstants() );
$ php test.php
Array
(
    [BAR] => 1
    [BAZ] => 2
)

PHP5になってから、PHPさんは関数からの脱却を図っている模様だ。

目的のものが標準関数に存在しなかったら、標準クラスを調べてみようというお話でした。

2011-03-16 地震

Text::ASCIITableによるアスキーテーブルレイアウト

MySQLの出力結果みたいなのが必要になったのでCPAN漁ってたらこんなの発見。

Text::ASCIITable - search.cpan.org

地味に凄いめちゃ便利

use Text::ASCIITable;

my @rows = (
    [1,'foo','2011-03-16 11:22:33'],
    [2,'hogehogehoge','2011-03-17 11:22:33'],
    [3,'uwaaaaa','2011-03-18 11:22:33'],
    [4,'dio','2011-03-19 11:22:33'],
    [5,'jojo','2011-03-20 11:22:33'],
);

my $t = Text::ASCIITable->new();
$t->setCols('id','name','created');
$t->addRow($_) for @rows;
print $t;
 $ perl asciitable.pl
 .-----------------------------------------.
 | id | name         | created             |
 +----+--------------+---------------------+
 |  1 | foo          | 2011-03-16 11:22:33 |
 |  2 | hogehogehoge | 2011-03-17 11:22:33 |
 |  3 | uwaaaaa      | 2011-03-18 11:22:33 |
 |  4 | dio          | 2011-03-19 11:22:33 |
 |  5 | jojo         | 2011-03-20 11:22:33 |
 '----+--------------+---------------------'

いいですねー。

あとサクサクっとハッシュ配列構造のデータを出力する場合はこんなかんじか

use Text::ASCIITable;

my @rows = (
    {'id' => 1,'name' => 'foo', 'created' => '2011-03-16 11:22:33'},
    {'id' => 2,'name' => 'hogehogehoge','created' => '2011-03-17 11:22:33'},
    {'id' => 3,'name' => 'uwaaaaa','created' => '2011-03-18 11:22:33'},
    {'id' => 4,'name' => 'dio','created' => '2011-03-19 11:22:33'},
    {'id' => 5,'name' => 'jojo','created' => '2011-03-20 11:22:33'},
);

if ( @rows ) {
    my @keys = keys %{$rows[0]};
    my $t = Text::ASCIITable->new();
    $t->setCols(@keys);
    $t->addRow(@$_{@keys}) for @rows;
    print $t;
}

いいですねー。

他にもオプション等で色々指定できるみたいですが、とりあえずこれだけできりゃもうおkですね。

2011-03-11 精緻

PHP5.2とPHP5.3でArrayObjectの挙動が違う話

ハマッタのでメモ。

<?php

$a = new ArrayObject(array('test' => 1));

print_r($a);

これをPHP5.2とPHP5.3で実行すると以下のようになる

# PHP5.2
ArrayObject Object
(
    [test] => 1
)

# PHP5.3
ArrayObject Object
(
    [storage:ArrayObject:private] => Array
        (
            [test] => 1
        )

)

PHP5.3の場合、なにやらデータの持ち方が新しくなったのかstorage:ArrayObject:privateとか言うのが増えてる。

これはおそらくstorageというprivate変数配列のデータを持つようになったという感じか。まぁそれ自体は問題ない。

問題は以下のコード

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject($a);

print_r($b);

実行結果

# PHP5.2
ArrayObject Object
(
    [test] => 1
)

# PHP5.3
ArrayObject Object
(
    [storage:ArrayObject:private] => ArrayObject Object
        (
            [storage:ArrayObject:private] => Array
                (
                    [test] => 1
                )

        )

)

PHP5.2のときにはArrayObjectにArrayObjectを渡しても配列として処理されていたが、PHP5.3からはArrayObjectがネストされてしまう。

正直ArrayObjectってのは配列シュミレートするもののはずなのでArrayObjectをオブジェクトとして保存してしまうPHP5.3の仕様には聊か首を捻らざるを得ない。

さらに怖いのが、この状態でもちゃんと配列として動いてしまうのでネストされてることに気付かないということだ。

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject($a);

print($b['test']); # ちゃんと「1」と表示される

つまり普通に扱ってる分には配列として動いてくれるので、めちゃくちゃネストしちゃっててもぜんぜん気付かない。

気付いたときには

ArrayObject Object
(
    [storage:ArrayObject:private] => ArrayObject Object
        (
            [storage:ArrayObject:private] => ArrayObject Object
                (
                    [storage:ArrayObject:private] => ArrayObject Object
                        (
                            [storage:ArrayObject:private] => ArrayObject Object
                                (
                                    [storage:ArrayObject:private] => ArrayObject Object
                                        (
                                            [storage:ArrayObject:private] => ArrayObject Object
                                                (
                                                    [storage:ArrayObject:private] => ArrayObject Object
                                                        (
                                                            [storage:ArrayObject:private] => Array
                                                                (
                                                                    [test] => 1
                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

こんなことになってるかもしれない。(ってかなってたw)

ArrayObjectを良く使う人はPHP5.3では注意しましょう!

ちなみに解決方法としては色々あるだろうけど、ArrayObjectに渡すときにarrayにキャストするとかしましょう。

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject((array)$a); // array型へキャスト

2010-12-21 歴史

「Webを支える技術」読了

久しぶりに本を読みませうと神の意思が降りてきたので第一弾は「Webを支える技術」を読むことに。


Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)


なんせ前評判は高かったし、発売後も高評価続出だしとずっと読まなきゃなーと思ってた一冊です。

いやーーーー、ようやく読み終わった。

なかなか読み応えのある素晴らしい書籍でした。これは素晴らしいとしか言いようがないね。うん素晴らしい。

個人的に一番面白かったのが第2章のWebの歴史。

今までまったく意識してなかったのでなるほどなるほどそういう歴史的理由があったのかとかブツブツ独り言言いながら楽しく読めました。

優れた音楽家は、その楽曲が作られた当時の時代背景や作曲家の生まれ育った環境等を勉強することで、より良い演奏ができるようになる、という話に似ているような気がします。って音楽家の話は勝手に今思いついただけですが。

とにかくWebプログラマなら必読の一冊と言えるでしょう。

ただし、まったくの初心者にはオススメしません。

Webプログラムの実践経験が無い人がこの本を読んでも書いてある意味をなんとなくは理解できても実際にどう適用されるのか何が何だかさっぱり分からないと思うので、ある程度実際に経験を積んでから読むのが理想的かなぁと思います。

そうそう話変わって、なんか梅田に国内最大級の本屋がオープンしたみたいなので近々ちょっと行ってみようかな。