Debugging a collection iterator

I have a collection (internally a FilterIterator), that starts with 3 elements and has a rejection that reduces that to 2. But running a foreach on it processes only a single element. I’m trying to debug this, but at a loss as to where I can put a useful breakpoint.

I’m using CakePHP 3.8.6, and PHPStorm. If I put a breakpoint on the foreach line and step into it, it goes into the reject function of the CollectionTrait, where it’s going to call my callback function, and the call stack indicates that this is called from the standard CallbackFilterIterator. Other breakpoints can find me inside the __debugInfo function.

The collection does know that it’s got 2 items in it, and if I add toArray() in the foreach, then it iterates over all the elements. (I am using this to work around this particular issue in the short term, but I don’t like not knowing what’s actually wrong, because it throws every other iteration on collections everywhere in my application into question.) Adding ->rewind() before the foreach has no effect. Uses of the same collection elsewhere in the code seem just fine. (Note: Not strictly the same object, but a separate collection generated by the exact same code on the exact same input, so should be the same for all intents and purposes.)

This really should be rock-solid, I’d have thought. I can’t think of what might be breaking this. But even more frustrating, I can’t seem to debug what’s going wrong. :frowning:

Is it possible to put some dummy step into the process that you can break on?

$x = 1; //a meaning less statement that can serve as a break point

This ‘safe’ stepping stone in the river might allow you to then look around at the other values and figure out what is happening.

I can step through the contents of the foreach loop. All the variables are set as I expect for the first pass through. When it gets to the end of the loop, it simply doesn’t go back to the start of the loop, it carries on to whatever is after it.

Breaking inside the loop isn’t useful, in other words. I need to break somewhere in the iterator where it’s deciding whether there are more items to iterate over.

And there is no way to place the stepping-stone break in the iterator callback? Or is breaking in there not allowed at all?

Or that’s still not where you need to see?

Seems that the underlying iterator is a base PHP class which cannot be stepped into, like substr, etc.

Hmm…

Isn’t your FilterIterator a class you’ve written that extends php’s FileIterator? with your specific implementation of accept()?

An alternative would be to use the cake Collections->filter(). You should be able to step into the callable you provide to satisfy that… At least I know I routinely debug from inside those callables

It’s not my FilterIterator class, it’s Cake’s, which is the result of using the stock filter call. The data in the collection is, as far as I can tell, all correct, as is my callable. It’s the next function that I think would be instructive to step into, but Cake’s FilterIterator doesn’t re-implement that, so the actual implementation (from the PHP base class) is presumably written in C.

Im not sure if I fully understand what are you doing.

Cant you check printing with debug() on first line of the filter and last line (check filtered/not filtered) to see if all three items are being processed at least.

Can you share a reduced sample snippet to see any errors/bugs?

My filter function is being called. If I put a breakpoint in it, it is hit three times, and it correctly returns true for two of them. I have multiple other places where this exact code is working just fine (the collection is being created in an accessor on an entity). In this one place, I can very simply write:

foreach ($items as $item) {
    $x = 1;
}

and when stepping through, the $x = 1 line will only be hit once, while:

foreach ($items->toArray() as $item) {
    $x = 1;
}

will hit it twice.

Does phpstorm have configured to show the values of the collection automatically? can you disable that?

It may have something like issue #8438

It may explain why it works with toArray instead of the collection

This also breaks if I’m not debugging it, and PHPStorm isn’t involved at all. That’s why I started trying to debug it in the first place.

Well, it has to be the iterator, the data or the interaction of these two specific players…

Is it only one specific set of three particular elements that causes the problem. Can you send other sets through and have them work?

If it’s just these elements then we have to examine them for problems.

If nothing works in the filter… Can you write the code using a Reduce instead?