2007-07-04 (水)
■ Zend Framework 自作コンポーネント用サンプルをアップデート
ようやく時間が取れたので、Zend Framework 1.0.0 を少しチェックしてみた。 試してみたところ、1.0.0 RC3 までは動いていたサンプルが 1.0.0 では動かなくなっていたので、とりあえずその対処をしておいた。 ダウンロードは以下のいずれかのページからどうぞ。
ここからは、何が今までと非互換になっていたかという話。 具体的には、ChangeLog に載っている ZF-1654 の修正 が影響している。 一応、この辺の説明は マニュアルのここ に書かれているが、もっと端的に書くと、 「views ディレクトリの下にあるディレクトリ、ファイルの名前はすべて小文字にしなければいけない」 という制約が加わっている。 つまり、今までは Registration のコントローラに対して Registration/index.phtml というビューのファイルを用意したりしていたが、 それが registration/index.phtml のように小文字にしないとダメになった。
この辺の細かい仕様は、はっきり言ってもう訳が分からないので、 混乱を避けるためには、コントローラ名やアクション名は小文字に統一して、 ピリオドやハイフンやアンダーバーを含んだ名前は使わない、とした方が良さそうだ。
2007-07-07 (土)
■ TableSorter plugin for jQuery の Tips
テーブルをソートできるようにする JavaScript はいろいろあるが、 TableSorter plugin for jQuery はカラムの種類(数値、日付、文字列など)を自動判別してくれる優れもので、 いろいろとカスタマイズもできるので、自分はこれを愛用している。 先日、PukiWiki の counterlist.inc.php プラグイン に組み込んでみたので、その時に調べたことを書いておく。
sortDir: 1 に設定すると、デフォルトで降順になる
このパラメータを設定することでデフォルトのソート順を変更できる。 ただしすべてのカラムが降順になってしまうので、いまいち使いづらいかも。
カラムの種別やフィルタを追加できる
例えば以下のコードを追加すると、整数のカラムだけデフォルトで降順にすることができる。 add_to_front でなく add という関数もあるが、 それだと他の parser が先に使われてしまうのでうまくいかない。 add_to_front を使うことで、この parser の優先順位を先に持ってくることができる。
jQuery.tableSorter.parsers.counter = {
id: 'counter',
is: function(s) {
return s == parseInt(s);
},
format: function(s) {
return s;
},
sorter: function(a, b) {
return b[1] - a[1];
}
};
jQuery.tableSorter.analyzer.add_to_front(jQuery.tableSorter.parsers.counter);
なお jQuery のメーリングリストによると、このプラグインの Ver.2.0 の開発が始まったらしい。
今までとは非互換になるそうだが、今まで以上に便利になりそうなので期待している。
2007-07-10 (火)
■ 相対 URI の定義について
相対 URI について調べ物をしていて、 BugTrack2/213 - PukiWiki-dev を読んでいたところ、次のような書き込みがあった。
<a href="?hoge"> は Another HTML-lint で怒られたと思います。
えぇ!? と思い、Another HTML-lint でチェックしてみると、確かに怒られる。 だが、怒られた理由の説明を読んでもどうも納得がいかないので、 RFC1945 を見てみると、URI の定義が以下のように書かれていた。
URI = ( absoluteURI | relativeURI ) [ "#" fragment ]
absoluteURI = scheme ":" *( uchar | reserved )
relativeURI = net_path | abs_path | rel_path
net_path = "//" net_loc [ abs_path ]
abs_path = "/" rel_path
rel_path = [ path ] [ ";" params ] [ "?" query ]
この定義を見る限りでは、?hoge というのは立派に相対 URI だと思う。 Another HTML-lint の方が間違っているんじゃないか?
そう思ってもう1度説明を読んだところ、Another HTML-lint の判定は RFC1738 に基づいた簡易的なもので、相対 URI のことはあまり考慮していないっぽい。 なので、相対 URI として ?hoge というのを使っても特に問題ないだろう、たぶん。
2007-07-14 (土)
■ treeview.inc.php プラグイン Ver.1.0 を公開
PukiWiki でいわゆるエクスプローラ風のツリーメニューを設置するためのプラグインを作成した。
前身の pagetree.inc.php プラグイン を、 JavaScript が使えるように改良したものだが、 中身は全く別物になっているので、別プラグインとしてリリースすることにした。 以下に特徴を書いておく。
- MenuBar ページに #treeview と書くだけで手軽に設置できる
- JavaScript が無効でも使える
- JavaScript が有効の場合には、クリックすることでメニューの折り畳み・展開ができる
- クロスブラウザ対応 (IE5.5, IE6, IE7, Firefox, Opera, Safari で確認済み)
- 生成した HTML をキャッシュする機能を搭載
最初は Yahoo! UI Library のような既存のライブラリを使うことも考えたが、 あれだと JavaScript が使えない場合に身動きが取れなくなってしまうので、 JavaScript が無効でも使えることを第一条件として作ってみた。 こういう仕組みのツリーメニューはかなり珍しいはず。
2007-07-16 (月)
■ treeview.inc.php プラグイン Ver.1.1 を公開
treeview.inc.php プラグイン をバージョンアップした。変更点は以下の通り。
- JavaScript のイベント処理の簡略化
今まではツリーメニューの1つ1つの要素に対してイベントを登録していたが、 livedoor Reader についての記事にもっと簡単な方法が載っていたので、 その方法をパクらせてもらった。
具体的に書くと、 ツリーメニューの一番外側の div 要素にのみ onclick のイベントを登録しておき、 どの要素がクリックされたかは event.target や event.srcElement で判別して、 それに応じた処理を実行するようにした。
2007-07-20 (金)
■ Ajax (AHAH) での文字化けを防ぐための Web サーバの設定
Ajax を使って、次のようなことをするコードを書いてみた。 (やりとりするのが XML でなく HTML なので、正確には Ajax でなく AHAH)
- Web サーバのあるディレクトリに EUC-JP で書かれた HTML ファイルを置いておく
- 表示中のページ (文字コード EUC-JP) の特定の箇所にそれを Ajax で読み込む
ところがやってみると、 途中で文字コードが UTF-8 に変換されてしまうらしく文字化けしてしまう。 charset を EUC-JP だと指定してやったところ、とりあえず文字化けを回避できたようなので、 Apache と lighttpd の場合のやり方をメモしておく。 なお、HTML ファイルは /var/www/ajax ディレクトリの下に置いてあるものとする。
Apache の場合
/var/www/ajax ディレクトリの .htaccess ファイルに以下のような設定を追加する。 (.htaccess で設定できない場合は、httpd.conf 辺りで同等の設定を行う)
AddType "text/html; charset=EUC-JP" .html
lighttpd の場合
lighttpd.conf にこんな設定を付け加える。
$HTTP["url"] =~ "^/var/www/ajax/" {
mimetype.assign = (
".html" => "text/html; charset=EUC-JP"
)
}
Apache 1.3.10 以降なら、これでもOK。(2007/07/28 追記)
AddCharset EUC-JP .html
2007-07-25 (水)
■ 関数の返り値をリファレンスにすることの効果について検証
PHP では関数の返り値をリファレンスにする (return-by-reference) ことができるが、 マニュアル などを読む限りでは、別にリファレンスで返さなくても、 リファレンスカウンティングの仕組みによって自動的に最適化されるっぽい。 ただ、返り値が配列の場合はどうなのか、というのがどうもよく分からなかったので実験してみた。 用意したのはこんな関数。
function getLargeArray()
{
$array = array(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
:
:
980, 981, 982, 983, 984, 985, 986, 987, 988, 989,
990, 991, 992, 993, 994, 995, 996, 997, 998, 999
);
return $array;
}
これを次の条件を変えた時にどうなるか調べてみる。
- 関数の返り値をリファレンスにする場合としない場合
- $array を static にした場合としない場合
つまり、具体的に書くと、以下の4通りを試してみる。
function getLargeArray()
{
$array = array(
...
);
return $array;
}
$array = getLargeArray();
function &getLargeArray()
{
$array = array(
...
);
return $array;
}
$array =& getLargeArray();
function getLargeArray()
{
static $array = array(
...
);
return $array;
}
$array = getLargeArray();
function &getLargeArray()
{
static $array = array(
...
);
return $array;
}
$array =& getLargeArray();
それぞれのケースで、 getLargeArray() を 10000 回呼び出して所要時間を計ってみた。 3回ずつ測定した時の平均値を以下に示す。 使用した PHP のバージョンは 5.2.3 だが、 念のため PHP 4.3.10 でやってみても同じような結果になった。
| non-static | static | |
|---|---|---|
| return-by-value | 2.961 | 1.538 |
| return-by-reference | 2.942 | 0.022 |
理屈はよく分からないが結果だけ見ると、 関数の返り値が static な配列の場合には、 リファレンスで返すことが有効だと思って良さそうだ。
2007-07-26 (木)
■ PukiWiki 用プラグイン pagetree.inc.php Ver.2.1 を公開
pagetree.inc.php プラグイン をバージョンアップした。変更点は以下の通り。
- 全ページ名のリストをソートしないで済むようにして高速化
- リンクを相対 URL 形式に変更
- コードの整理
他にも部分部分で高速化したので、どのくらい速くなったかを調べるため、 プラグインを 5000 回実行するのにかかった時間を計ってみた。 Ver.1.6 の仕様に合わせるため、Hide top-level leaves のオプションはオフにして測定した。 結果は以下のようになった。
| Ver.1.6 | Ver.2.0 | Ver.2.1 |
|---|---|---|
| 8.712 | 8.179 | 6.696 |
| 8.639 | 8.043 | 6.763 |
| 8.655 | 8.152 | 6.665 |
ページ数とかの条件にもよるので、一概には言えないが、 今までのバージョンより 20〜30% くらい速くなっている。 これ以上改善するのはたぶん無理だと思うが、 全ページ名のリストのソートという重そうな処理をなくせたので、 ページ数が多い場合でもそれなりに使えるようになったと思う。
2007-07-28 (土)
■ PukiWiki 用プラグイン ajaxtree.inc.php Ver.0.9 を公開
PukiWiki 用に Ajax を使ったツリーメニューのプラグインを作成した。 説明をここに書くのは面倒なので、詳しくはこちらの専用ページを見てほしい。
先日公開した treeview.inc.php プラグイン と機能は同じだが、こちらの方が転送量が少なくて済むという利点があるし、 なにより Ajax を使っているというのがカッコいい気がする。 ということで、個人的にはこちらのプラグインの方を本命にしたいと思っている。
2007-07-30 (月)
■ PHP と JavaScript の URL エンコードの違い
PHP に出力させた HTML ファイルを JavaScript から Ajax (AHAH) で直接読み込む、 ということをやろうとしている。この時、
- PHP の rawurlencode() は RFC 1738 に基づくエンコード
- JavaScript の encodeURIComponent() は RFC 2396 に基づくエンコード
のように PHP と JavaScript ではエンコード処理が微妙に異なるので、 その辺を調整してやらないといけない。
この辺りのページを読むと、両者の違いは、
!~*()'
の6文字をエンコードするかどうか、のようだ。 だから、PHP 側か JavaScript 側でつじつま合わせをしてやれば良いが、 アスタリスクがファイル名に使えないことを考えると、* → %2A の方向に変換するのが良さそうに思える。 ということで、JavaScript で rawurlencode() 互換の関数を作ってみた。
function rawurlencode(str) {
return encodeURIComponent(str)
.replace(/!/g, "%21")
.replace(/'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
.replace(/\*/g, "%2A")
.replace(/~/g, "%7E");
};
もっと上手に書けるのかもしれないが、一応これで期待通りに動いてくれる。
2007-07-31 (火)
■ jQuery の If-Modified-Since の処理
PukiWiki の ajaxtree.inc.php プラグイン 用に、 Ajax のこんなコードを見よう見まねで書いた。
function ahah(url, target) {
var req = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
if (req) {
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
......
}
}
req.open("GET", url, true);
req.setRequestHeader("If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT");
req.send("");
}
};
If-Modified-Since に過去の時刻をセットして、 Web サーバから毎回確実にレスポンスを受け取るようにしているが、 これだとちょっと非効率な感じがする。 jQuery の Ajax のコードは If-Modified-Since の処理をきちんとやっているようなので、 上のコードの代わりに jQuery の Ajax 用関数を使ってみた。
試してみたところ、ちょっと期待はずれな部分があって、 画面遷移せずに同じファイルを GET する場合には 2回目以降のリクエストで 304 が返ってくるのだが、 一旦画面遷移すると普通に 200 が返ってきてしまうようだ。
jQuery のコードを見ると、Last-Modified の情報をせっせとキャッシュしているのだけれど、 JavaScript の変数として保存しているので、画面遷移すると情報が失われてしまっている。 クッキーに保存すればいいんじゃないかとも思うが、 それはそれでいろいろと大変そうな気がする。
今回の場合は、もともと、 画面遷移しない間は同じリクエストを繰り返さないように JavaScript のコードを書いていたので、 jQuery を使わなくても上のコードで十分っぽい。
■ Zend Framework 1.0.1 がリリース
Zend Framework 1.0.1 が出ていた。 アナウンスと ChangeLog にリンクを張っておく。
細かいバグ修正がメインのようだが、 特に Zend_Gdata と Zend_Db がパワーアップされているらしい。 とりあえずバージョンアップしておくか。
ただ最近の Zend Framework は、 明記せずにこっそり仕様変更、というのをよくやらかしてくれるから要注意。 バージョンアップしたら動かなくなった、というのを過去何度も経験しているから。

# sonots [変な結果ですねぇ。自分も試してみて、さらに function getLargeArray() { $arra..]
# revulo [どの部分にどれだけの時間がかかっているのか、これだけでは分からないですね。 1.$array 初期化にかかる時間 ..]