イテレータってなに?
要するに反復子ですね。PHPでプログラムする時に自前でこのパターンを用意することはあまりないと思いますが、一応基礎ということで。ちなむと、PHPでは、iterator インターフェースが用意されていて、それを実装すると foreach で 普通に回せます。あーだこーだ自前のイテレータについて考えるよりは、標準イテレータ実装した方が分かり易いかも知れないですね。
イテレータの構造
- イテレータ - 反復子
- アグリゲータ - 多分、データ詰める役(今回だとarray関数ですかね)
構造どうこうより実際に見てもらいましょう。
<?php
// 標準イテレータと互換のインターフェースにしています
interface Iteratable {
public function rewind();
public function valid();
public function current();
public function next();
}
class IteratorUser {
private $_Object = null;
public function __construct ( $obj ) {
if ( !( $obj instanceof Iteratable ) )
throw new Exception ( 'むりっす' );
$this->_Object = $obj;
}
public function run ( $fnc ) {
for ( $this->_Object->rewind(); $current = $this->_Object->current(); $current = $this->_Object->next() ) {
$result = $fnc ( $current );
}
}
}
class ArrayList implements Iteratable{
private $_InnerList = array ();
private $_Index = 0;
public function __construct ( $arr ) {
if ( !is_array ( $arr ) )
throw new Exception ( '無理っす' );
$this->_InnerList = $arr;
}
public function valid () {
return count ( $this->_InnerList ) > $this->_Index;
}
public function rewind () {
$this->_Index = 0;
}
public function current () {
return $this->_InnerList[$this->_Index];
}
public function setToCurrent ( $obj ) {
$this->_InnerList[$this->_Index] = $obj;
}
public function next () {
return $this->_Index++;
}
public function key () {
return array_keys ( $this->_InnerList );
}
}
class ArrayList2 extends ArrayList implements Iterator { }
print 'こっちは自前イテレータ' . "\n";
$obj = new IteratorUser ( new ArrayList ( array ( 1, 2, 3, 4, 5 ) ) );
$obj->run ( function ( $i ) {
var_dump( $i );
});
print '普通に標準イテレータ' . "\n";
foreach ( new ArrayList2 ( array ( 1, 2, 3, 4, 5 ) ) as $elm ) {
var_dump ( $elm );
}
コメント
イテレータは要するに、PHPで言うとforeachして走査するための実装ですね。でもforeachがどうのっていうより、このパターンの本質は走査と操作を分けましょうっていうことだと思うのです。イテレータがどうのっていうのはともかく、その走査と操作は分けましょうという考え方は大事だと思います。