【问题标题】:Is changing an objects state/contents appropriate Iterator usage (php)正在更改对象状态/内容适当的迭代器用法(php)
【发布时间】:2011-07-12 16:29:55
【问题描述】:

考虑一个用于存储项目集合的对象,但该集合可能会因预定义的上下文而异。

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。使用迭代器是否矫枉过正?此外,迭代器是否应该改变它正在迭代的对象的状态/内容?

【问题讨论】:

  • return $this->steps[ $this->key() ]; - steps 在哪里声明?有完整的代码会更容易回答。
  • 哎呀,对不起。属性“步骤”应该是“上下文”。我编辑了我的问题。您还需要更多信息吗?
  • 我真的不明白你在这里想要完成什么。这是你习惯用其他语言做的事情吗?我什至不得不问这个问题我觉得很愚蠢,因为我确信这里有更多经验丰富的程序员会为我的无知而抱怨。
  • 嗯,所以 foreach 循环对我来说有点新,指向$myContainer 的指针在每次迭代中都会改变吗?
  • @andho:$myContainer 是一个迭代器对象,因此对于每个“循环”,它的“当前”方法都被称为返回 $key 和 $value 的值。如果您对 foreach 不熟悉,请查看 foreach doc page。它非常适合遍历数组。但是,它也可以用于iterate over an object

标签: php iterator


【解决方案1】:

上面的代码很简洁,但我觉得很脏,因为我从来没有真正使用过 $key 或 $value。

您还没有展示getContextIterator() 的内部结构,因此很难提出具体建议。通常可以通过实现OuterIterator interace 或仅实现Iterator interface 在PHP 中创建可迭代对象。这两个接口都是预定义的,然后您可以将您的对象与next()foreach 等一起使用。

我假设您已经实现了 OuterIterator 之类的东西。如果您改为实施 OuterIterator,您将获得一些速度优势 AFAIK。

使用迭代器是否过大?

不,不会这么说。正如您所说,迭代器非常适合集合。不过,我只是将其更改为 SPL 迭代器。

此外,迭代器是否应该改变它正在迭代的对象的状态/内容?

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

因此,即使对于您正在迭代的对象内部的“更多”更改,只要清楚它的作用,它就可以更改。反例:如果你迭代一个数组并且每次迭代前一步它都会打乱元素是没有用的。

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

【讨论】:

  • 感谢您的回复 hakre。我实际上忘了包括一个重要的细节。 “Container”类已经实现了 IteratorAggregate 以循环遍历集合项。当需要检查每个上下文时,“ContextIterator”是一个额外的迭代器。
  • "...只要清楚它的作用,它就可以改变。" -- 我想这就是我被挂断的地方,因为我不确定它是否清楚。
  • @jbarreiros:嗯,看起来你已经创建了一个迭代器来返回一个特定的实例。这有点虚假,使事情变得比它需要的更复杂。例如:为什么someMethod()是通过迭代器访问的?它看起来像是已经可迭代的集合类上的一种可迭代装饰器。还是集合类本身不可迭代,而您的迭代器是它的装饰器?这一切都是有效的,但是我理想情况下会保持简单和流畅/解耦。它仍然可以有效。例如。在 foreach 中实例化迭代器。
  • 你创建了一个迭代器来只返回一个特定的实例”是正确的。我创建了“ContextIterator”来返回 Container 类的特定实例。 -- 集合类已经是可迭代的以允许遍历$contents 中的项目,这就是为什么“ContextIterator”,正如你所说的,是集合类上的一个装饰器。 -- 在foreach中实例化迭代器似乎确实让代码更清晰一点。
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
  • 2020-03-21
相关资源
最近更新 更多