tags:

views:

399

answers:

3

I have an object that implements ArrayAccess, Iterator and Countable. That produces a nigh-perfect array masking. I can access it with offsets ($object[foo]), I can throw it into a foreach-loop, and many other things.

But what I can't do is give it to the native array iterator functions (next(), reset(), current(), key()), even though I have implemented the required methods from Iterator. PHP seems to stubbornly try to iterate through its member variables, and entirely disregards the iterator-methods.

Is there an interface that would hook the object to the remaining array-traversing-functions, or am I stuck with what I have?

Update: IteratorAggregate doesn't seem to be the answer either. While it is used in foreach-loops, the basic array iterator functions don't call the methods.

A: 

Is ArrayIterator not what you're looking for? Or what about ArrayObject, which seems to be SPL's interface for what you're trying to achieve.

Peter Bailey
Actually, those are not interfaces, but implementations. But, now that you mention it, ArrayObject does seem to react as expected to function calls such as reset($arrayObject);
Henrik Paul
+3  A: 

One way to get this to work is to define your own iterator in a separate class, and then tell your main class to use that new iterator instead of the default one.

class MyIterator implements Iterator {
  public function key() {
    //
  }

  public function rewind() {
    //
  }

  // etc.

}

class MyMainClass implements IteratorAggregate {
  private $_data = array();

  // getIterator is required for the IteratorAggregate interface.
  public function getIterator() {
    return new MyIterator($this->_data);
  }

  // etc.

}

Then you should have as much control as you need. (And you can reuse your own MyIterator across a number of classes).

No testing done on the above, but the principle is correct, I believe.

Hope this helps!

majelbstoat
For some strange reason, this doesn't work for me. It's as if the custom iterator never gets called with the basic array iterator functions.
Henrik Paul
The ArrayObject implementation already has a get/set convention for the Iterator
Peter Bailey
Sure, but ArrayObject is a concrete class, not an interface, so you have to extend it, not implement it. And, given that you can only extend from one class, I'd choose to do it this way. Better separation of concerns too, I think. YMMV :)
majelbstoat
+4  A: 

Recent changes in PHP prevent ArrayIterators form being manipulated using the standard array functions (reset, next, etc).

This should be restored soon: http://news.php.net/php.internals/42015

ringmaster