肉とビールとパンケーキ by @sotarok

少し大人になった「肉とご飯と甘いもの」

Services_Twitter-0.1.0 betaがリリースされたので日本のと比較してみた


Services_Twitterといえば、悠希さんの Services_Twitter が日本では有名ですが、Proposalにいまさら入っていたServices_Twitterが7/26にリリースされました。


ほげ〜と思ってざっとソース追って両者の比較してみました。
と、まじめにやろうと思ってたんですが、なんか疲れてるので(なんだそれw)、目についた部分だけとりあえず。


対象環境


Services_Twitter(悠希さん)のほうが、PHP4.3.0以上を対象としているのに対し、Services_TwitterPEAR本家)*1のほうはPHP5.1.0を対象としています。まぁGO PHP5をがんばらなきゃいけないPHPの公式パッケージ郡としては当然でしょう。


Services_TwitterPEAR本家)のほうはマジックメソッド __get() を使い、簡単にfactoryでStatuses、DirectMessagesなど個別のクラスを呼び出すことができます。

Services_TwitterPEAR本家):Services/Twitter.php

<?php
// snip...
    public function __get($var)
    {
        if (!isset(self::$methods[$var])) {
            throw new Services_Twitter_Exception(
                'Method (' . $var . ') is not implemented'
            );
        }

        return $this->factory(self::$methods[$var]);
    }
// snip...


これにより、以下のサンプルコード(ちなみにサンプルコードは、パッケージの中に大量に入っています。)のように、アローでつないでメソッドにアクセスすることができます。

<?php

$twitter = new Services_Twitter($user, $pass);
$res = $twitter->statuses->update($update);

通信


これはかなり大きな違いですが、通信部分が違います。

Services_Twitter(悠希さん)のほうは、ちゃんとsocket開いて通信しているのに対して、Services_TwitterPEAR本家)のほうは curl 使って通信しています。

当該部分のソース。

Services_Twitter(悠希さん): Services/Twitter/Connector.php

<?php
// snip...
        // send request
        $fp  = fsockopen($url['host'], $url['port']);
        if (!$fp) return false;
        fputs($fp, $request);
        $response = '';
        while (!feof($fp)) $response .= fgets($fp, 4096);
        fclose($fp);
// snip...


Services_TwitterPEAR本家): Services/Twitter/Common.php

<?php
// snip...
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, $this->options['userAgent']);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_USERPWD, $this->user . ':' . $this->pass);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->options['timeout']);

        $sets = array();
        foreach ($params as $key => $val) {
            $sets[] = $key . '=' . urlencode($val);
        }

        if ($method == 'POST') {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $sets));
        } else {
            if (count($sets)) {
                $uri .= '?' . implode('&', $sets);
            }
        }

        curl_setopt($ch, CURLOPT_URL, $uri);
        $res = trim(curl_exec($ch));

        $err = curl_errno($ch);
        if ($err !== CURLE_OK) {
            throw new Services_Twitter_Exception(curl_error($ch), $err, $uri);
        }

        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if (substr($code, 0, 1) != '2') {
            $xml = @simplexml_load_string($res);
            if ($xml instanceof SimpleXMLElement && isset($xml->error)) {
                throw new Services_Twitter_Exception(
                    (string)$xml->error, Services_Twitter::ERROR_UNKNOWN, $uri
                );
            }

            throw new Services_Twitter_Exception(
                'Unexpected HTTP status returned from API', $code, $uri
            );
        }

        curl_close($ch);
// snip...


えーcurlかよーとか思いつつ・・・w socketで通信してる悠希さんのやつのほうが素敵だなあ。

そして、取得したXMLファイルはSimpleXMLで解析してますね。*2まぁさすがにPHP5でXML扱うなら当然ダヨネーという感じでしょうか。(暗黒のnamespaceは出てきませんしw)


どっちにしてもさ、こういう場で共通して使われることのないHTTP_Requestってw。そういう面倒な処理の共通化のためにPEARパッケージがあるんじゃないんかい、とか思いつつ。

フォーマット

レスポンスのフォーマットには、Services_TwitterPEAR本家)のほうは、 xml 決めうちで、解析にはSimpleXML使っています。

一方、Services_Twitter(悠希さん)のほうは JSON で取得していて、Jsphonを使って解析しています。PHP5.2以降なら json 関数が使えるんですけどねぇ。

クライアントアプリ

Services_Twitter(悠希さん)のほうは、このライブラリを使って何らかの形でクライアントアプリケーションを実装されることが想定されていて、Twitterクライアントアプリを設定するメソッドが用意されています。(クライアントアプリは、発言の末尾に「from hogehoge」と表示されます。)

で、ヘッダに付加して送信するわけですね。


Services_Twitter(悠希さん): Services/Twitter.php

<?php
// snip...
        if ($this->_app_name !== null) {
            $req->addHeader('X-Twitter-Client', $this->_app_name);
        }
        
        if ($this->_app_ver !== null) {
            $req->addHeader('X-Twitter-Client-Version', $this->_app_ver);
        }
        
        if ($this->_app_url !== null) {
            $req->addHeader('X-Twitter-Client-URL', $this->_app_url);
        }
// snip...

修正:現状は、ヘッダで送信するのではなく update時にsourceとして指定するらしいです。悠希さんの本体のほうも、CodeReposでは対応されているようです。 http://coderepos.org/share/changeset/13614
id:hiro_y さんありがとうございます :)

いいですねこれは。これで、各発言の後ろに自分のクライアントアプリを表示することができるようになるということですね。(実際には、それが使われ始めてから反映されるまでは時間がかかるようです。参考: )


一方、PEAR本家のほうはこれを設定する方法はありません。(たぶん。テキトーに言ってるかも?)

まとめ


まぁ、大まかに見てこんなとこでしょうか。最後のほうてきとーです。
PHP4にこだわらない環境では、Services_TwitterPEAR本家)を使ってみるのも良いのかな、と思いますが、実装の仕方は悠希さんのやつのほうが素敵かも。でも、インターフェース的にはたしかに__getとか使ってるPEAR本家のほうが使いやすいかもしれません。

しかし、あんなAPI制限のついているTwitter APIなんてもはや使う価値なんてないんじゃないか?とか思ったりしてね。(ぉ
なんともいえんたい。


wassr使えばいいんじゃないかな・・・・w

*1:ていうか、先に出てたのは悠希さんのほうなので、「本家」と呼ぶのはなんとなく気が引けますが、まぁ、本家PEARサイト、という意味だけです。

*2: @simplexml_load_string($res); ←わろた