Hi everyone,

I've been taking another look at iterators lately, and compiled trunk and
started experimenting with traits.  I also looked at an old mail from Marcus
regarding iterator_apply, and  find myself wondering why there isn't just an
'apply' method as part of the Iterator hierarchy itself.

   Although PHP had support for the pseudo-type callback when the Iterator
interface was introduced, I'm not sure why an 'apply' function would have
been omitted from the original Iterator interface.  Clearly with
iterator_apply out there, there is no functional gain by adding a method
into the Iterator hierarchy, however I think it would be more cohesive with
the OO paradigm the Iterator hierachy presents .. there is already
array_walk and friends for the global function gang :)  And now with
closures the idea of an 'apply' method is even more enticing .. yes I'm
thinking of Javascript code like JQuery's each() ...


I can tell why it wouldn't have been added after the original interface was
in the wild though, because changing the interface would break tons of
client code.  However a second interface could be added and all client code
would continue to function


interface InnerIterator

{

  function apply($mCallback [, mixed $...]);

}


Rather than extend Iterator, InnerIterator should be left independent so it
can be incorporated into implementors of OuterIterator (see below).  Then
concrete Iterator(s) could implement this new interface as well


class ArrayIterator implements Iterator, InnerIterator { … }


I'm not sure what the best implementation at the engine level would be, but
with the advent of traits that would clearly be one option,  a simple
implementation could be something like


trait InnerIteratorImpl

{

    public function apply($mCallback)

    {

        $aArgs = func_get_args();

        array_shift($aArgs);

        $aCallbackArgs = array_merge(array($this), $aArgs);

        return iterator_apply($this, $mCallback, $aCallbackArgs);

    }

}


Then the ArrayIterator definition could become


class ArrayIterator implements Iterator, InnerIterator

{

  use InnerIteratorImpl;

  ...

}


I hardly doubt this is necessary inside the engine, as I'm sure there can be
a common C function which is used to implement the interface, but that would
be for more educated people to decide.


Classes which implement IteratorAggregate (ArrayObject for example) would
then return implementors of InnerIterator, which still implement Iterator as
they originally did.  Classes which implement OuterIterator could now also
implement InnerIterator as well, and the 'apply' method in that case can
simply delegate to the wrapped Iterator as they currently do for implemented
Iterator methods.


class CachingIterator implements OuterIterator, InnerIterator

{

    public function apply($mCallback)

    {

      return $this->getInnerIterator()->apply(func_get_args());

    }

}


A quick example from userspace with the addition


$oArrayObj = new ArrayObject(array(5, 4, 3, 2, 1));

$oArrayObj->getIterator()->apply(function(Iterator $oIt) {

  var_dump($oIt->current());

  return true;

});


At the end of the day it's just syntactic sugar since iterator_apply is
there, but in my book it would be welcome sugar ;)  I would also argue that
even with traits, implementing this notion in userspace is slower (needless
conversion) and messy, imagine a subclass of ArryObject for example that
implements InnerIterator, inside of getIterator, it has to convert the
ArrayIterator to a new userspace class InnerArrayIterator or some such,
which implements InnerIterator, before returning it.


Your thoughts appreciated!


-nathan

Reply via email to