イッソノ〜そろそろPHPでの最強CouchDBライブラリ決めようぜ (第1回)


ナカシマ「イソノ〜。今日もテンプレートエンジン界のオーバーテクノロジーで遊ぼうぜ〜」
イソノ「そうだな〜。今日はスクレイピングした結果をさくっと保存したいな〜。*1
ナカシマ「それならやっぱりCouchDBナウいよ。」
イソノ「NoSQLって言うんだっけ?」
ナカシマ「CouchDBはドキュメント指向DBって括りに入るね。」
イソノ「最近だと、MongoDBのほうがPHP界隈(日本の)だと注目浴びてるんじゃないか?」
ナカシマ「それを言いだすと、この記事がなんの意味もないじゃないか。。。」
ナカシマ「Futonというアドミン画面があるからvar_dump好きにはオススメだよ」


イソノ「で、PHPCouchDBを扱うにはどうしたらいいんだい?」
イソノ「CouchDBの導入記事にはcurlが載ってるからexec("curl"..なのかな?」
ナカシマ「お前はSnoopyか!お前はSnoopy.class.phpか!」
ナカシマ「CouchDBAPIはHTTPだから、httpリクエスト送れば良いってことになるけど、
CouchDB用のライブラリはいくつかあるんだ。」
イソノ「あ、CouchDBwikiを見ると4つばかりライブラリが載ってるからそれの中から選ぶんだね」
ナカシマ「バカを言うなよ。CouchDBを扱うPHPライブラリは10は越えるよ。」
イソノ「まるでフレームワークの状況じゃないか。。」
ナカシマ「以下にリストとして載っけてみたよ」
http://wiki.github.com/sasezaki/diggin/php-couchdb-clients


ナカシマ「フレームワーク同様、各ライブラリは特徴があるし、選定条件も状況によってまちまちになると思うんだ」
イソノ「最強のを選ぶんじゃなかったのかい?」
ナカシマ「え?」
イソノ「え?」
ナカシマ「対応するPHPのバージョンってのがあるけど、CouchDB用の選定基準になるのはいくつかあるよ。」
イソノ「どういうことが挙げられる?」
ナカシマ「並べてみようか」

- PHPのバージョン
- 対応するCouchDBのバージョン
- ライブラリが対称とする範囲("モデル"に特化している場合がある)
- View対応
- AttachMent対応
- ViewServer利用
- リクエスト送信方法(fget,stream,curl,pecl_http)
- JSONエンコード/デコード方法
- 他のフレームワーク・ライブラリとの連携・依存性

ナカシマ「CouchDB自体がまだ開発途上だから対応するCouchDBのバージョンってのも重要だね」
ナカシマ「だから必然的にメンテされてるかってのも重要だと思うんだ」

----- Object_Freezer

イソノ「条件にはライセンスとかテストコード入ってるかとかは入らないのかい。」
ナカシマ「もちろんそうだね。」
イソノ「じゃあテストPHPUnit作者のObject_Freezerってのを……」
ナカシマ「ちょっとまった。ライブラリ名確認したかい?」
イソノ「オブジェクトをふりーずするんだろ?」
ナカシマ「これはPHPオブジェクトのストアリングの一つにCouchDBがあるってだけなんだ。」
レスポンスステータスコードをチェックしてるのか謎なところもあるんでCouchDBクライアントとしては全然おすすめできないね。」

----- PHP-on-CouchとPHPillow

イソノ「じゃあ有力なクライアントって何?」
ナカシマ「今のところ知名度も考慮すると、PHP-on-CouchとPHPillowだろうね」
イソノ「PHP-on-Couchってこの前IBMの記事に載ってた?*2
ナカシマ「そう。更新が活発でCouchDB0.9からでの特殊リクエストメソッド"COPY"も意識されてるようだしね。枯れてないとも言えるけど」
イソノ「やたらあるprint_rのコメントアウトが気になるんだけど。。」


ナカシマ「PHPillowはezのコミッターでもある人が作者なんだ。」
イソノ「ezって最近Apache Incubatorにプロポーザル出したあのez?」
ナカシマ「そう。PHPコミッター(というか毎コミ記事・後藤さんネタ元)であるJohannes Schlüter
も紹介してるしね。*3
イソノ「CouchDB自体もApacheプロジェクトだし、相性抜群って訳だ。」
ナカシマ「PHPillow自体がezコンポーネントって訳じゃないらしいけどね。」

----- Phly_CouchとSopha

ナカシマ「次に紹介したいのは、ZFのコミッターでもあるShahar EvronのSophaだ。」
ナカシマ「shevronはZend PHP
カンファレンス2009で”Introduction CouchDB with PHP"っていう講演をしてるよ」
イソノ「あれ、ZFのコミッターが作ったものってリードのマシューが作ったPhly_Couchがあるよね。」
ナカシマ「たしかに、Phly_CouchはZFのプロポーザルにあがったりしてるけど、Attachmentに対応してる節はないししばらくメンテされてないみたいなんだ」
イソノ「あれ、このSophaって中身見るとZFそのものを使ってないの?」
ナカシマ「そう、1.8ぐらいの頃のZFから一部コンポーネントをポートしてあるよ。」
イソノ「なんでそんなことを。。」
ナカシマ「オトナ ノ ジジョウ ワカリマセン」


……第2回につづく(?)

PHP 5.3ではXpathを拡張できる

タイトルでは誇張して煽ってみてますが、PHP5.3より前ではXSLTProcessorでしかついてなくて正直へえ(´・∀・`)だった感じのregisterPhpFunctions()がDOMXPathについたことによって超すごいことになってたんですよ奥さん!(私は今頃しった)


Premature Optimization > XPath regular expression matching in PHP 5.3
PHP: DOMXPath::registerPhpFunctions - Manual


詳細は上記リンク先とマニュアル見てもらえば良いんですが、
$domPath->query("//html:a[php:functionString('preg_match', '$regex', @href)> 0]")
て感じで正規表現にマッチするもの取得とか、ユーザー定義関数もレジストできるので複雑なこともできますね!
たしかperlxpathのモジュールでも正規表現が使えるとか見たような気がするんですけど、これでウラヤマシイーとか思うこともなくなりましたー(かな?)

PHPでYouTube動画をダウンロードするWozozo_WWW_YouTubeをリリース。

インストール

sudo pear install openpear/Wozozo_WWW_YouTube

使い方

<?php
require_once 'Wozozo/WWW/YouTube.php';
Wozozo_WWW_YouTube::download('gQf_QTsvXCU'); //YouTubeのvideoID
Wozozo_WWW_YouTube::download('http://www.youtube.com/watch?v=gQf_QTsvXCU'); //URL指定でもOK

//直にダウンロードせず、ダウンロードURL取得
$youtube = new Wozozo_WWW_YouTube;
echo $youtube->getVideoInfo('gQf_QTsvXCU')->makeDownloadUrl(); 


Zend Frameworkコマンドようプロパイダーはもちろんつけてますので、

zf enable config.provider Wozozo_WWW_YouTube_Tool_YoutubeProvider

としてもらうと


て、感じで実行できます。


保存先はデフォルトでは$_SERVER['PWD']ですが、
configの'save'にファイルパスを指定、もしくはコールバック関数を渡して保存方法を変更できます。
詳しくは今のところソース見てください。
http://openpear.org/repository/Wozozo_WWW_YouTube/trunk/src/Wozozo/WWW/YouTube.php



え?僕はyourfilehost用のZFコマンドが欲しいって?
すでにありますよ。
http://openpear.org/package/Wozozo_Libido_Tool_Provider_YourfilehostProvider

RecursiveIteratorIteratorIteratorIterator


(※画像はI love unicodeの人のスライドの「Code, Ideas, People」からの借用です。)


PHPの無名関数を使って再帰処理を行う : アシアルブログ

さて本題の再帰処理です。RubyのArray#flattenと同じようなものを実装してみます。Array#flattenはネストした配列を1次元の配列に平滑化するメソッドです。無名関数にする必要はないですが、再帰のサンプルと言うことで...

 $flatten = function($array) use(&$flatten) {
   $result = array();
  
   foreach ($array as $value) {
     if (is_array($value)) {
       // 配列ならこの無名関数を再度呼び出す
       $result = array_merge($result, $flatten($value));
     } else {
       $result[] = $value;
     }
   }
  
   return $result;
 };

こっちのほうが短いっすよ!

$flatten = function (array $a) {
    $results = array();
    array_walk_recursive($a, function ($v, $k) use (&$results) {
        //$results = array_merge($results, array($k => $v)); だとキーがあって重複したときにダメ
        $results = array_merge($results, (array)$v);
    });

    return $results;
};

$array = array('a' => 1, 5, array(3, array(22, 5, array(9, 500))), 12);
echo join (', ', $flatten($array)); //1, 5, 3, 22, 5, 9, 500, 12


PHP5.3で無名関数が搭載されたので、コールバックを使う頻度はあがると思います。(実際にlithiumには無名関数とarray_map、array_walkの組み合わせがいくつかあるし、ZFリードによるミニマルAOPPhly_PubSubだってコールバックありきだし、またBlankaでも!)
しかしながらブログ記事用のサンプルに突っ込むのは野暮ですけれども、無名関数をそのまま再起するのはモダンじゃない感じがします。ファイル読み込みや、多次元配列内のオブジェクトのメソッドを呼ぶ場合など、遅延評価なことを行うことも考えられます。再帰的に処理するわけなので、みんな大好きSPL系のRecursive群の出番ですね。

$array = new RecursiveIteratorIterator(new RecursiveArrayIterator($array),           
                                       RecursiveIteratorIterator::LEAVES_ONLY);

ちなみに、↑これをiterator_to_arrayするさいは各個別のarrayのキーはかぶってるので第2引数falseを加えないとだめです。

echo join(', ', iterator_to_array($array, false)); // 1, 5, 3, 22, 5, 9, 500, 12

文字列結合演算子

echo は , か . かって話
http://d.hatena.ne.jp/sotarok/20100321/1269200776

を受けての話ですが、"."こと文字列結合演算子は思い込みでリテラル以外はちょっと微妙になるとおもってました。

<?php

class ToString
{  
    private $value;

    public function __construct($value)
    {  
        $this->value = $value;
    }

    public function __toString()
    {
        return (string) $this->value;
    }
}

echo "a".new ToString('b')."c"; //abc

...実行できるんだ。。


個人的にはvar_dumpっぽい感じだから変数が個別に評価されてく感じですっきりするので","多用してますが。


パフォーマンス的な話は、ユーザーノートにも記載がありますね。
http://php.net/manual/ja/language.operators.string.php

今の pear list -a

PHP5.3使ってます!キリッ!とかのたまってる割にはメインのpearはphp5.2の
(というかubuntuの\phpなので)だったりするので、pearも5.3のbinにしとこうということで、各パッケージ入れ直したりする前よう昔こんなの入れてたのねー的なメモ。

INSTALLED PACKAGES, CHANNEL __URI:
==================================
PACKAGE               VERSION STATE
PEAR_PackageProjector 0.1.3   beta
Pit                   1.0.0   stable
Services_Photozou     1.2.0   stable
phpman                0.1.3   beta

INSTALLED PACKAGES, CHANNEL DOC.PHP.NET:
========================================
(no packages installed)

INSTALLED PACKAGES, CHANNEL OPENPEAR.ORG:
=========================================
PACKAGE                 VERSION STATE
HTML_CSS_Selector2XPath 0.1.0   beta
IgnoreExceptionIterator 0.1.3   stable
Maple4_DocTest          0.2.2   alpha
Net_Q4M                 0.1.0   beta

INSTALLED PACKAGES, CHANNEL PEAR.HATOTECH.ORG:
==============================================
PACKAGE            VERSION STATE
IO_OutputBuffering 0.1     beta

INSTALLED PACKAGES, CHANNEL PEAR.HORDE.ORG:
===========================================
PACKAGE VERSION STATE
Yaml    1.0.1   stable

INSTALLED PACKAGES, CHANNEL PEAR.MICHELF.COM:
=============================================
(no packages installed)

INSTALLED PACKAGES, CHANNEL PEAR.PHING.INFO:
============================================
PACKAGE VERSION STATE
phing   2.3.3   stable

INSTALLED PACKAGES, CHANNEL PEAR.PHP.NET:
=========================================
PACKAGE                 VERSION  STATE
Archive_Tar             1.3.3    stable
Benchmark               1.2.7    stable
CodeGen                 1.0.6    stable
CodeGen_PECL            1.1.2    stable
Config                  1.10.11  stable
Console_Color           1.0.2    stable
Console_Getargs         1.3.4    stable
Console_Getopt          1.2.3    stable
Console_Table           1.1.3    stable
Event_Dispatcher        1.1.0    stable
File_Find               1.3.0    stable
HTML_CSS                1.5.4    stable
HTML_Common             1.2.5    stable
HTTP_Client             1.2.1    stable
HTTP_Request            1.4.4    stable
HTTP_Request2           0.3.0    alpha
Image_GraphViz          1.2.1    stable
MDB2                    2.4.1    stable
Net_CDDB                0.3.0    alpha
Net_Socket              1.0.9    stable
Net_URL                 1.0.15   stable
Net_URL2                0.3.1    beta
Net_UserAgent_Mobile    1.0.0RC3 beta
PEAR                    1.9.0    stable
PEAR_PackageFileManager 1.6.3    stable
PHP_CodeSniffer         1.2.0    stable
PHP_CompatInfo          1.9.0    stable
Structures_Graph        1.0.2    stable
Text_Figlet             1.0.1    stable
VersionControl_SVN      0.3.1    alpha
XML_Parser              1.3.2    stable
XML_Util                1.2.1    stable

INSTALLED PACKAGES, CHANNEL PEAR.PHPUNIT.DE:
============================================
PACKAGE       VERSION STATE
File_Iterator 1.2.0   stable
PHPUnit       3.4.11  stable
phploc        1.0.0   stable

INSTALLED PACKAGES, CHANNEL PEAR.PROJECT-P.JP:
==============================================
(no packages installed)

INSTALLED PACKAGES, CHANNEL PEAR.SYMFONY-PROJECT.COM:
=====================================================
(no packages installed)

INSTALLED PACKAGES, CHANNEL PEAR.ZFCAMPUS.ORG:
==============================================
PACKAGE VERSION STATE
ZF      1.10.2  stable

INSTALLED PACKAGES, CHANNEL PECL.PHP.NET:
=========================================
PACKAGE    VERSION STATE
PDO        1.0.3   stable
PDO_SQLITE 1.0.1   stable
inclued    0.1.0   alpha
pecl_http  1.6.5   stable
sqlite3    0.6     alpha
xdebug     2.0.5   stable

INSTALLED PACKAGES, CHANNEL PHPCOMMONS.SOURCEFORGE.JP/PEAR:
===========================================================
PACKAGE VERSION STATE
Commons 1.0.3   stable

@see おまえ達がインストールしているPEAR パッケージはなんなんだぜ?
http://project-p.jp/halt/anubis/blog_show/662

ZendFramework 勉強会 #2

行ってまいりました。
http://events.php.gr.jp/events/show/91
株式会社paperboy&co.様会場&懇親会費提供ありがとうございます!


で発表中、咳ゴホンゴホンしまくっててマジすいません!!!(;´Д`)
私の発表のスライドは以下。