Skip to content

Fix support for IteratorAggregate and EmptyIterator objects in loops#4141

Merged
fabpot merged 1 commit into
twigphp:4.xfrom
fabpot:loop-fixes
Jul 16, 2024
Merged

Fix support for IteratorAggregate and EmptyIterator objects in loops#4141
fabpot merged 1 commit into
twigphp:4.xfrom
fabpot:loop-fixes

Conversation

@fabpot

@fabpot fabpot commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

No description provided.

@fabpot fabpot merged commit 98e67ea into twigphp:4.x Jul 16, 2024
@fabpot fabpot deleted the loop-fixes branch July 16, 2024 16:42
} while ($seq instanceof \IteratorAggregate);
$this->seq = $seq;
} elseif (is_iterable($seq)) {
$this->seq = $seq;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here $seq is more than probably Iterator or IteratorAggregate but that's almost "internal"...

Internal (built-in) classes that implement this interface can be used in a foreach construct and do not need to implement IteratorAggregate or Iterator.

Not sure if this could happen IRL .. but maybe a elseif ($seq instanceof \Iterator) would be more precise here ?

do {
$seq = $seq->getIterator();
} while ($seq instanceof \IteratorAggregate);
$this->seq = $seq;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHPStorm was not happy so i looked a bit and...

IteratorAggregate::getIterator() does not return an Iterator but only a Traversable ...

so after the loop here $this->seq could totally be a simple array

Would something like this work 'out of the box' ?

if (is_array($seq))
 // ArrayIterator($seq)
elseif ($seq instanceof Traversable)
  // IteratorIterator ($seq)
else 
  // EmptyIterator

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best would be to create a PR with examples of something that fails and the fix for those tests.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well i spend time and clearly IRL that won't ever happen.

The last possibilities would be those classes PHP say can be used in "foreach" while not implementing "Iterator" directly, but i cannot find an example.

Sorry for the waste of time here.

$this->seq = is_iterable($seq) ? (is_array($seq) ? new \ArrayIterator($seq) : $seq) : new \ArrayIterator([]);
if (is_array($seq)) {
$this->seq = new \ArrayIterator($seq);
} elseif ($seq instanceof \IteratorAggregate) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a much simpler way: using IteratorIterator

$this->previous = ['valid' => false, 'key' => null, 'value' => null];
$this->current = ['valid' => $this->seq->valid(), 'key' => $this->seq->key(), 'value' => $this->seq->current()];
if ($this->seq->valid()) {
$this->previous = ['valid' => false, 'key' => null, 'value' => null];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we always assign previous ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was something i wonder, but there is only one situation getPrevious() can be called without beeing set, it's if someone call "loop.previous" in the else part of its for ... else .... endfor.

Because the node inside the for block can only be called if there is something in the loop (so when this->seq->isValid() is true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and in such case, we still want it to be able to return null as value, not a PHP error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #4169

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants