2011-07-12 6 views
1

アイテムのコレクションを格納するオブジェクトを考えてください。ただし、コレクションは事前定義されたコンテキストによって異なる場合があります。オブジェクトの状態/内容を適切に変更するイテレータの使用法(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を使用していることはないので、私にとっては汚いと感じています。イテレータのオーバーキルを使用していますか?さらに、イテレータがオブジェクトの状態/内容を変更した場合、それは反復処理されますか?

+0

'return $ this-> steps [$ this-> key()];' 'steps'はどこに宣言されていますか?フルコードで答えるのがより簡単になります。 –

+0

おっと、申し訳ありません。プロパティ「ステップ」は「コンテキスト」であったはずです。私は私の質問を編集しました。まだ詳しい情報が必要ですか? – jbarreiros

+0

私はあなたがここで達成しようとしているものを実際には得られません。これはあなたが他の言語でやっていたことですか?私はここに私の無知で嘆きに行くより多くの経験豊富なプログラマーがいると確信しているので、これを尋ねなければならないために愚かな気がする。 – pthurmond

答えて

1

上記は素晴らしくコンパクトですが、実際には$ keyや$ valueを使用していないので、私には汚い感じがします。

getContextIterator()の内部を表示していないので、具体的な提案をするのは難しいです。一般に、OuterIterator interaceを実装するか、Iterator interfaceを実装するだけで、PHPで反復可能なオブジェクトを作成することができます。私はあなたがOuterIteratorのようなものを実装しました仮定など

両方のインターフェイスには、あらかじめ定義されており、あなたはその後、next()であなたのオブジェクトを使用することができ、foreach。代わりにOuterIteratorを実装すると、AFAIKのスピードを上げることができます。

イテレータのオーバーキルを使用していますか?

いいえ、そうは言いません。イテレーターは、コレクションを持っていると言ったコレクションには非常に適しています。私はそれをSPLイテレータに変更するだけです。

さらに、イテレータがオブジェクトの状態/内容を変更すると、反復処理されますか?

実際には、少なくとも反復の内部ポインタについては、各イテレータが行います。しかし、私はそれがあなたの懸念ではないと思っていますが、すでに軽くなっているかもしれません。

オブジェクト内の「より多くの」変更についても、反復処理中であっても、それが何であるかがわかっている限り変更されても大丈夫です。 Counter-Example:配列を反復処理し、反復が一歩前進するたびに要素をシャッフルすると便利ではありません。

しかし、これが完全に有効で有用な場合もあります。だから一般的なルールではなく、何をしたのかを決める。

+0

お返事ありがとうございます。私は実際に重要な細部を含めるのを忘れていました。 "Container"クラスは、コレクション項目をループするためのIteratorAggregateをすでに実装しています。 "ContextIterator"は、各コンテキストを調べる必要があるときには余分なイテレータです。 – jbarreiros

+0

"...それが何をしているかがわかっている限り、それが変わっても大丈夫です。" - それは私がそれがはっきりしていたかどうか分からなかったので、私がハングアップしたところだと思います。 – jbarreiros

+1

@jbarreiros:うーん、特定のインスタンスを返すだけのイテレータを作成したようです。これはやや偽のもので、必要以上に複雑になります。例えば:イテレータを通して 'someMethod()'にアクセスするのはなぜですか?これは、既に反復可能なコレクションクラスの一種の反復可能なデコレータのように見えます。または、コレクションクラス自体が反復可能ではないので、反復子はそのためのデコレータですか?これはすべて有効なことですが、理想的には物事をシンプルかつ流動的に/デカップルに保ちます。しかしそれはまだ有効です。例えば。 foreachのイテレータをインスタンス化します。 – hakre