PHPのIteratorを実装してみた

PHPの面白い小技です。
業務で使ったので公開します。
 
PHPのIteratorを実装して、
処理を簡潔に記述する方法。
 
※例外やSRPなどのクラス設計は無視。
Iteratorのサンプルとして提供します。
 
TwitterAPIのOAuthのサンプルにもなるかもです。
 
 
■処理概要
---------
 
Twitterで
指定ユーザの全リストの全ユーザ情報（今回はスクリーン名のみ）を取得する処理。
 
■詳細
-----
 
TwitterでOAuth認証した後に、
APIのList/Menberにアクセスしてユーザ情報を取得する。
 
■コード
-------
 
###（Iterator実装前）

 
```php: 
// Listに含まれるユーザ情報を取得
function getMemberFromList( $lid ) {
 
    $connect;
    $next_cur = '-1';
    $results = array();
 
    do {
        $req = false;
        $api_url = "https://api.twitter.com/1/lists/members.xml?list_id={$lid}&cursor={$next_cur}";
        $method = "GET";
        $req = $connect->OAuthRequest( $api_url, $method );
 
        if ( empty($req) ) return false;
 
        $objXml = simplexml_load_string($req);
 
        // 次ページ番号
        $next_cur = (string)$objXml->next_cursor;
 
        foreach($objXml->users->user as $user) {
            $results[] = (string)$user->screen_name;
        }
 
    } while( $next_cur > 0 );
 
    return ( !empty($results) )? $results: false;
}
```
 
###（Iterator実装後）
 
リクエスト処理とページング処理を隠蔽。
う～ん、実にシンプル。二重ループは大目にみて（＠＠

```php: 
// Listに含まれるユーザ情報を取得
function getMemberFromList( $lid ) {
 
    $results = array();
    $clsLM = new TListMember($lid);
 
    // 一つの繰り返しが、１リクエスト取得分となる
    // 対象が2ページあれば2回、1ページであれば1回まわる。
    foreach( $clsLM as $lm ) {
        foreach($lm->users->user as $user) {
            $results[] = (string)$user->screen_name;
        }
    }
 
    return ( !empty($results) )? $results: false;
}
```
 
■コード詳細
-----------

###（Iteratorを実装した「TListMemberクラス」）


```php: 
/**
 * TwitterAPI list/memberクラス
 */
class TListMember implements Iterator {
 
  private $index = 0; //現在位置
  private $objXml;
  private $connect;
  private $lid;
 
  public function __construct( $lid )
  {
    $this->lid = $lid;
 
    // twitteroauthを利用
    require_once('twitteroauth/twitteroauth.php');
 
    $consumer_key = "■■■■";
    $consumer_secret = "■■■■";
    $access_token = "■■■■";
    $access_token_secret = "■■■■";
 
    // OAuthオブジェクトの生成
    $this->connect = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);
    $this->connect->format = "xml";
 
    $this->objXml = $this->getMemberList();
  }
 
  /**
   * 現在の要素を返す
   */
  public function current() {
    return $this->objXml;
  }
 
  /**
   * 現在の要素のキーを返す
   */
  public function key() {
    return $this->index;
  }
 
  /**
   * 次の要素に進む
   */
  public function next() {
    $this->index++;
    $this->objXml = $this->getMemberList((string)$this->objXml->next_cursor);
  }
 
  /**
   * イテレータの最初の要素に巻き戻す
   */
  public function rewind() {
    $this->index = 0;
    $this->objXml = $this->getMemberList();
  }
 
  /**
   * 現在位置が有効かどうかを調べる
   * @return 成功した場合に TRUE を、失敗した場合に FALSE を返します。
   */
  public function valid() {
     return !is_null($this->objXml);
  }
 
  // メンバー情報取得
  private function getMemberList( $next_cur = -1 ){
 
    if ($next_cur == 0) return null;
 
    $req = false;
    $api_url = "https://api.twitter.com/1/lists/members.xml?list_id={$this->lid}&cursor={$next_cur}";
    $method = "GET";
    $req = $this->connect->OAuthRequest( $api_url, $method );
 
    if ( empty($req) ) return null;
 
    return simplexml_load_string($req);
  }
}
```