修改对象的状态/内容是否适合使用迭代器(php)


Is changing an objects state/contents appropriate Iterator usage (php)

考虑一个用于存储项集合的对象,但是该集合可能根据预定义的上下文而变化。

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迭代器。

进一步说,迭代器应该改变它正在迭代的对象的状态/内容吗?

实际上每个迭代器都是这样,至少对于迭代的内部指针是这样。但我认为这不是你所关心的,但可能已经减轻了。

因此,即使在你迭代的对象中有"更多"的变化,只要清楚它的作用,它的变化是完全可以的。反例:如果你迭代一个数组,并且每次迭代前一步都会对元素进行洗牌,这是没有用的。

但在其他情况下,这是完全有效和有用的。所以决定做了什么,而不是一般规则。