Archive for the 'PHP' Category

『Fast CakePHP』を買っていた

2008年01月10日 written by fjkktkys

fastcakephp

年末にぶらりと寄った書店に売っていたのをうっかり買ってみました。
いいなと感じた点を3点ほどあげてみます。

  1. CakePHPで用意されている各種ビューの使い方が分かって非常に良かったです
  2. rewriteまわりがハマりどころですが、その辺のハウツーがあって良い
  3. 一連の処理の流れの図があるので、そこからハックもできる

今年も個人的に1本はなんらかのアプリを作って行きたいです。

Fast CakePHP (LLフレームワークBOOKS # 4)
秋田 真宏
技術評論社 (2008/01/09)
売り上げランキング: 344
おすすめ度の平均: 3.0

3 CakePHPを手早く知るにはよい一冊だが

PHPのPDOのprepareについて

2007年06月09日 written by fjkktkys

スクリプトのprepareとサーバのprepare

PHPのPDOを使いながらクエリーログを見ていたら、
見慣れないものが目に入ってきました。

CODE:
  1. 391 Connect     admin@localhost on pdo_test
  2. 391 Prepare     [1] INSERT INTO users SET name = ?
  3. 391 Execute     [1] INSERT INTO users SET name = '9f732d76d9f2f0b4e62c8091c99a2334'
  4. 391 Quit

Prepareという行なのですが、PerlのDBIを使っていた分には見たことがありませんでした。

そこで以下を参照して、
MySQL 関数 (PDO_MYSQL)

CODE:
  1. $pdo = new PDO('mysql:host=localhost;dbname=pdo_test;charset=utf-8;unix_socket=/tmp/mysql.sock', "username", "password");
  2. $pdo->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, true);

上のようにPDOの設定をして同じSQLを実行すると

CODE:
  1. 392 Connect     admin@localhost on pdo_test
  2. 392 Query       INSERT INTO users SET name = 'f071c916f507876b8f67735faa0e015f'
  3. 392 Quit

いつものようなログが取れましたとさ。

ここで認識できるのは、スクリプト側でのprepareとMySQLサーバサイドでのprepareが別物だということ。恥ずかしながらそうとも知らずに今までPerlのDBIでprepareを使っておりました。
(prepareを使う理由は、プレースホルダーを使って外部入力を安全にSQLに挿入するためです。)

ベンチマークしてみる

で、以下のようなSQLを用意して、
init.sql

CODE:
  1. USE pdo_test;
  2.  
  3. DROP TABLE IF EXISTS users;
  4. CREATE TABLE users (
  5.     id   INT(16) PRIMARY KEY AUTO_INCREMENT,
  6.     name VARCHAR(32) UNIQUE NOT NULL
  7. );

以下のような、スクリプトを用意します。
pdo_test.php

CODE:
  1. <?php
  2. $pdo = new PDO('mysql:host=localhost;dbname=pdo_test;charset=utf-8;unix_socket=/tmp/mysql.sock', "username", "password");
  3. //$pdo->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, true);
  4.  
  5.  
  6.  
  7. //foreach ( range(1, 100000) as $i) {
  8. insertByPrepare($pdo);
  9. //insertByQuery($pdo);
  10. //}
  11.  
  12. //insertByPrepareLoop($pdo);
  13.  
  14. function insertByPrepare ($pdo) {
  15.     $sth = $pdo->prepare("INSERT INTO users SET name = ?");
  16.     $sth->execute( array(hash('md5', microtime())) );
  17. }
  18.  
  19. function insertByQuery ($pdo) {
  20.     $pdo->query("INSERT INTO users SET name = '" . hash('md5', microtime()) . "'");
  21. }
  22.  
  23. function insertByPrepareLoop ($pdo) {
  24.     $sth = $pdo->prepare("INSERT INTO users SET name = ?");
  25.     foreach ( range(1, 100000) as $i) {
  26.         $sth->execute( array(hash('md5', microtime())) );
  27.     }
  28. }
  29. ?>

ベンチマークには疎いので、適当で手動なんですが、
このスクリプトのコメントアウトのあたりを外したりつけたりして、
コマンドラインから以下を繰り返しです。

CODE:
  1. # mysql <init.sql
  2. # time php pdo_test.php

結果

当たり前ですが、prepareしたステートメントハンドラをループで回すという、
prepareの意味通りに使うパターンが一番早くなりました。

insertByQuery [PDO::MYSQL_ATTR_DIRECT_QUERY, true]
php pdo_test.php  10.14s user 4.24s system 32% cpu 44.907 total

insertByQuery
php pdo_test.php  13.83s user 8.65s system 33% cpu 1:07.68 total

insertByPrepareLoop [PDO::MYSQL_ATTR_DIRECT_QUERY, true]
php pdo_test.php  8.48s user 4.03s system 30% cpu 41.258 total

insertByPrepareLoop
php pdo_test.php  8.14s user 4.40s system 30% cpu 40.570 total

insertByPrepare [PDO::MYSQL_ATTR_DIRECT_QUERY, true]
php pdo_test.php  12.84s user 4.34s system 34% cpu 49.931 total

insertByPrepare
php pdo_test.php  18.05s user 10.15s system 36% cpu 1:17.68 total

ループを回さないところでprepareをすると少し遅いようです。
基本的に「PDO::MYSQL_ATTR_DIRECT_QUERY, true」にしておいて、サーバ側でprepareしないようにしておくと良さそうですね。

#余談
PHP5.1.xだと、LIMITなどで

CODE:
  1. $sth = $pdo->prepare('SELECT * FROM users LIMIT ?');

とやるとステートメントハンドラ自体が帰ってきません。
5.2.xでは解決されているバグのようです。

DBにJSONを突っ込む

2007年06月08日 written by fjkktkys

データベースの1カラムに配列を突っ込むのはお作法的にはあまりよろしくなくて、デリミタとして[|,]あたりを使ってカラムに突っ込んだりした過去もあった。

先日、それPHPのserialize関数でやってるよという話を聞いて割と目から鱗だった。連想配列も気軽につっこめます!でもPerlで読めないよ><みたいな話だった。

CPANモジュールを探したら案の定ありました。
The CPAN Search Site - search.cpan.org PHP::Serialization
Perlからも安心してPHPのserializeを扱えます。

でも時代はJSONでしょうとうことで、以下の記事とかを参照すると
よほど階層を深くしない限りは問題ない感じだ。
zuzara : PHP5.2.0でserialize()とjson_encode()はどちらが速いのか

バッドノウハウですが、DBに配列などを突っ込む時はJSONがよろしいようで。

tableタグで1から100を表示(PHP編)

2007年06月08日 written by fjkktkys

Unknown::Programming - tableタグで1から100を表示

コードははてダに書いていたのですが、バックスラッシュ化ける問題があったりするのと、こっちにコードなんかも書いていこうかということでちょうどいい例題。

PHPでやってみよう

CODE:
  1. <table>
  2. <?php foreach ( range(0, 9) as $r ) { ?>
  3.   <tr>
  4.   <?php foreach ( range($r * 10 + 1, ($r + 1) * 10) as $d ) { ?>
  5.     <td><?= $d ?></td>
  6.   <?php } ?>
  7.   </tr>
  8. <?php } ?>
  9. </table>

こんな感じかしら。

smartyを使うとこんな感じ。

CODE:
  1. <table>
  2. {section name=r start=0 loop=9}
  3.   <tr>
  4.   {section name=d start=1 loop=10}
  5.     <td>{$smarty.section.r.index*10+$smarty.section.d.index}</td>
  6.   {/section}
  7.   </tr>
  8. {/section}
  9. </table>

演算の記号のところに半角を入れるクセがついているのですが、半角を入れると思ったように動いてくれません><

以下参照です。
みるくぜりー | Smartyでfor文みたいな動きをさせるには

Perlのおかげさまで、for文で++とか条件書いたりすることができなくなりました><
あと個人的には、View部分でのecho/printは極力使わないようにしている感じです。