define('RIT_LEAVES_ONLY', 0);
define('RIT_SELF_FIRST', 1);
define('RIT_CHILD_FIRST', 2);
+define('RIT_CATCH_GET_CHILD', 256);
/**
* @brief Iterates through recursive iterators
{
private $ait = array();
private $count = 0;
+ private $mode = RIT_LEAVES_ONLY;
+ private $flags = 0;
/** Construct from RecursiveIterator
*
* @param it RecursiveIterator to iterate
- * @param flags Operation mode:
+ * @param flags Operation mode (one of):
* - RIT_LEAVES_ONLY only show leaves
* - RIT_SELF_FIRST show parents prior to their childs
* - RIT_CHILD_FIRST show all childs prior to their parent
+ * or'ed with the following flags:
+ * - RIT_CATCH_GET_CHILD which catches exceptions during
+ * getChildren() calls and simply jumps to the next
+ * element.
*/
function __construct(RecursiveIterator $it, $flags)
{
$this->ait[0] = $it;
+ $this->mode = $flags & 0xFF;
+ $this->flags = $flags & ~0xFF;
}
/** Rewind to top iterator as set in constructor
if ($it->valid()) {
if (!$it->recursed && callHasChildren()) {
$it->recursed = true;
- $sub = callGetChildren();
+ try
+ {
+ $sub = callGetChildren();
+ }
+ catch (Exception $e)
+ {
+ if (!($this->flags & RIT_CATCH_GET_CHILD))
+ {
+ throw $e;
+ }
+ $it->next();
+ continue;
+ }
$sub->recursed = false;
$sub->rewind();
if ($sub->valid()) {
RIT_CHILD_FIRST = 2
} RecursiveIteratorMode;
+#define RIT_MODE_MASK 0x000000FF
+#define RIT_CATCH_GET_CHILD 0x00000100
+
typedef enum {
RS_NEXT = 0,
RS_TEST = 1,
spl_sub_iterator *iterators;
int level;
RecursiveIteratorMode mode;
+ int flags;
zend_function *callHasChildren;
zend_function *callGetChildren;
zend_function *beginChildren;
} else {
zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
}
+
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ if (child) {
+ zval_ptr_dtor(&child);
+ }
+ object->iterators[object->level].state = RS_NEXT;
+ goto next_step;
+ }
+ }
+
ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL;
if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
if (child) {
intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
intern->iterators = emalloc(sizeof(spl_sub_iterator));
intern->level = 0;
- intern->mode = mode;
+ intern->mode = mode & RIT_MODE_MASK;
+ intern->flags = mode & ~RIT_MODE_MASK;
intern->ce = Z_OBJCE_P(object);
zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
if (intern->callHasChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
if (zend_is_true(retval)) {
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
if (EG(exception) && intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
- zval_ptr_dtor(&EG(exception));
- EG(exception) = NULL;
+ zend_clear_exception(TSRMLS_C);
if (zchildren) {
zval_ptr_dtor(&zchildren);
}
spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
- REGISTER_LONG_CONSTANT("RIT_LEAVES_ONLY", (long)RIT_LEAVES_ONLY, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("RIT_SELF_FIRST", (long)RIT_SELF_FIRST, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("RIT_CHILD_FIRST", (long)RIT_CHILD_FIRST, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_LEAVES_ONLY", (long)RIT_LEAVES_ONLY, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_SELF_FIRST", (long)RIT_SELF_FIRST, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_CHILD_FIRST", (long)RIT_CHILD_FIRST, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("RIT_CATCH_GET_CHILD", (long)RIT_CATCH_GET_CHILD, CONST_CS | CONST_PERSISTENT);
REGISTER_SPL_STD_CLASS_EX(FilterIterator, spl_dual_it_new, spl_funcs_FilterIterator);
REGISTER_SPL_ITERATOR(FilterIterator);