Hi internals, Userland classes that implement Traversable must do so either through Iterator or IteratorAggregate. The same requirement does not exist for internal classes: They can implement the internal get_iterator mechanism, without exposing either the Iterator or IteratorAggregate APIs. This makes them usable in get_iterator(), but incompatible with any Iterator based APIs.
A lot of internal classes do this, because exposing the userland APIs is simply a lot of work. I would like to add a general mechanism to make this simpler: https://github.com/php/php-src/pull/5216 adds a generic "InternalIterator" class, that essentially converts the internal get_iterator interface into a proper Iterator. Internal classes then only need to a) implement the IteratorAggregate interface and b) add a getIterator() method with an implementation looking like this: // WeakMap::getIterator(): Iterator ZEND_METHOD(WeakMap, getIterator) { if (zend_parse_parameters_none() == FAILURE) { return; } zend_create_internal_iterator_zval(return_value, ZEND_THIS); } This allows internal classes to trivially implement IteratorAggregate, and as such allows us to enforce that all Traversables implement Iterator or IteratorAggregate. Regards, Nikita