考虑一个用于存储项集合的对象,但是该集合可能根据预定义的上下文而变化。
Class Container implements IteratorAggregate (
protected $contexts; // list of associated contexts, example: array(0=>1,1=>3)
protected $contents; // array
public loadContents( $contextId ) { /* populates $this->contents*/ }
public getContexts() { /* populates $this->contexts */ }
...
public function getIterator() { return new ArrayIterator($this->contents); }
public getContextIterator() { return new contextIterator($this); }
}
迭代器如下:
Class contextIterator {
protected $container;
protected $contexts;
protected $currentContext;
public function __construct($container) {
$this->container = $container;
$this->contexts = $container->getContexts();
$this->currentContext = 0;
}
public current() {
$this->container->loadContents( $this->key() );
return $this->contexts[ $this->key() ];
}
public function key() { return $this->currentContext; }
public function next() { $this->currentContext++; }
public function rewind() { $this->currentContext = 0; }
public function valid() { return isset( $this->contexts[ $this->key() ] ); }
}
对于需要迭代检查每个上下文的少数情况,我做以下操作:
$myContainer = new Container();
foreach( $myContainer->getContextIterator() as $key => $value ) {
$myContainer->someMethod();
}
上面的代码很简洁,但是对我来说有点脏,因为我从来没有真正使用过$key或$value。使用迭代器是多余的吗?此外,迭代器应该改变它正在迭代的对象的状态/内容吗?
上面的代码很简洁,但是我觉得有点脏,因为我从来没有真正使用过$key或$value。
你没有展示getContextIterator()
的内部结构,所以很难提出具体的建议。一般来说,通过实现OuterIterator
接口或仅仅实现Iterator
接口,可以在PHP中创建可迭代的对象。这两个接口都是预定义的,然后你可以使用你的对象与next()
, foreach
等。
OuterIterator
。如果你实现OuterIterator
,你会得到一些速度上的好处。
不,我不会这么说的。迭代器对于集合来说非常好,就像你说的那样。我只是想把它改成SPL迭代器。使用迭代器是否多余?
进一步说,迭代器应该改变它正在迭代的对象的状态/内容吗?
实际上每个迭代器都是这样,至少对于迭代的内部指针是这样。但我认为这不是你所关心的,但可能已经减轻了。
因此,即使在你迭代的对象中有"更多"的变化,只要清楚它的作用,它的变化是完全可以的。反例:如果你迭代一个数组,并且每次迭代前一步都会对元素进行洗牌,这是没有用的。
但在其他情况下,这是完全有效和有用的。所以决定做了什么,而不是一般规则。