Wie verhalten sich die Iterator-Methoden von PHP valid (), current () und next ()?

8

Ich benutze PHP 5.3.6 von MAMP .

Ich habe einen Anwendungsfall, in dem es am besten wäre, PHPs Iterator Interface-Methoden, next() , current() und valid() zu verwenden, um durch eine Sammlung zu iterieren. Eine foreach Schleife funktioniert NICHT in meiner speziellen Situation. Eine vereinfachte while-Schleife könnte aussehen wie

%Vor%

Sollte der obige Code immer funktionieren, wenn $ iter PHP Iterator interface implementiert? Wie geht PHP%% c_de% mit Iteratoren um?

Der Grund, warum ich frage, ist, dass der Code, den ich schreibe, ein foreach oder ein ArrayIterator erhalten kann. Beide implementieren PHP MongoCursor interface, aber sie verhalten sich anders. Ich würde gerne wissen, ob es einen Fehler in der Mongo-Erweiterung von PHP oder PHP gibt.

Iterator gibt vor jeden Aufruf von ArrayIterator::valid() zurück - unmittelbar nachdem die next() erstellt wurde.

ArrayIterator gibt erst nach den ersten Aufruf von MongoCursor::valid() zurück. Daher wird die obige while-Schleife niemals ausgeführt.

Es besteht die Gefahr, dass sie ausführlich sind. Der folgende Code demonstriert diese Behauptungen:

%Vor%

Welche Implementierung ist korrekt? Ich fand wenig Dokumentation, um beide Verhaltensweisen zu unterstützen, und die offizielle PHP-Dokumentation ist entweder mehrdeutig oder ich lese sie falsch. Das Dokument für next() lautet:

  

Diese Methode wird nach Iterator :: rewind () und Iterator :: next () aufgerufen, um zu überprüfen, ob die aktuelle Position gültig ist.

Dies würde bedeuten, dass meine while-Schleife zuerst Iterator::valid() aufrufen soll.

Aber die PHP-Dokumentation für next() lautet:

  

Diese Methode wird nach jeder foreach-Schleife aufgerufen.

Dies würde bedeuten, dass meine while-Schleife wie geschrieben korrekt ist.

Zusammenfassend - wie verhalten sich PHP-Iteratoren?

    
meva 19.03.2012, 20:56
quelle

3 Antworten

8

Das ist eine interessante Frage. Ich bin mir nicht sicher, warum ein foreach nicht für dich funktioniert, aber ich habe ein paar Ideen.

Sehen Sie sich das Beispiel auf der Iterator-Referenzseite an. Es zeigt die Reihenfolge an, in der die interne Implementierung von foreach die Methoden Iterator aufruft. Beachten Sie insbesondere, dass bei der ersten Einrichtung von foreach der allererste Aufruf in rewind() erfolgt. Dieses Beispiel, obwohl es nicht gut kommentiert ist, ist die Grundlage für meine Antwort.

Ich bin mir nicht sicher, warum ein MongoCursor nicht für valid() bis nach next() zurückgibt, aber Sie sollten in der Lage sein, einen der beiden Objekttypen durch Aufruf von% zurückzusetzen. co_de% vor deiner Schleife. Sie hätten also:

%Vor%

Ich glaube, das sollte für Sie funktionieren. Wenn dies nicht der Fall ist, enthält die Mongo-Klasse möglicherweise einen Fehler.

Bearbeiten: Mike Purcells Antwort ruft richtig auf, dass ArrayIterator und Iterator nicht identisch sind. ArrayIterator implementiert jedoch Iterator, so dass Sie rewind() wie oben gezeigt auf jedem von ihnen verwenden können.

    
Jazz 19.03.2012, 21:38
quelle
7

Das Unterklassifizieren eines Iterators und eines Echos, wenn es aufgerufen wird, sagt Ihnen, wie es sich verhält.

Beispiel ( Demo )

%Vor%

Ausgabe

%Vor%

Dies entspricht dem Ausführen von

%Vor%

Die Reihenfolge, in der die Methoden aufgerufen werden, ist identisch mit einer benutzerdefinierten Iterator :

%Vor%     
Gordon 19.03.2012 21:37
quelle
4

Es scheint, dass Sie Iterator und ArrayIterator möglicherweise verwechselt haben, da jeder seinen eigenen valid() api-Aufruf hat.

  • Array-Iterator : next() usw. wird nicht explizit erwähnt. aber das Beispiel zeigt deutlich, was Sie in Ihrem OP erwähnt haben, um zu paraphrasieren; Es muss kein anderer AI-API-Aufruf durchgeführt werden, um festzustellen, ob das aktuelle Element des Arrays gültig ist.

  • Iterator : Wie Sie erwähnen: "Diese Methode wird nach Iterator aufgerufen: : rewind () und Iterator :: next () um zu überprüfen, ob die aktuelle Position gültig ist. "

Als solches würde ich bei ArrayIterator bleiben, da es das korrekteste Verhalten demonstriert, indem valid() korrekt feststellt, ob das aktuelle Element im Array gültig ist, ohne einen weiteren API-Aufruf machen zu müssen (next, rewind).

Wenn Sie möchten, dass Mongo sich so verhält wie AI, können Sie vor dem Start der while-Schleife eine Instanzprüfung hinzufügen:

%Vor%     
Mike Purcell 19.03.2012 21:37
quelle

Tags und Links