]> granicus.if.org Git - php/commitdiff
- Fix issues with iterators and excpetions
authorMarcus Boerger <helly@php.net>
Wed, 27 Jul 2005 22:19:01 +0000 (22:19 +0000)
committerMarcus Boerger <helly@php.net>
Wed, 27 Jul 2005 22:19:01 +0000 (22:19 +0000)
# update documentation
#
# In 5.2 we need to implement an event handler onException() to be invoked
# on exceptions during getChildren() calls. Its default implementation
# would simply rethrow the exception if the flag is not set and delete if
# if it was set. To do so the exceptions refcount needs to be increased
# before calling zend_clear_exception() to keep the exception alive but
# clear the control information.
#
# As a side note this is alos the easy solution to allow multi exception
# handling: Simply clear the engine's exception info and add a property
# called $previousException to the base exception and assign it from the
# already pending one.

ext/spl/internal/recursiveiteratoriterator.inc
ext/spl/spl_iterators.c

index 0e76de21dd6c0e857b48198ff8c8f68155eb3500..66cffc48752f804a42f70e0c0cce2d6c36672d36 100755 (executable)
@@ -12,6 +12,7 @@
 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
@@ -27,18 +28,26 @@ class RecursiveIteratorIterator implements OuterIterator
 {
        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
@@ -94,7 +103,19 @@ class RecursiveIteratorIterator implements OuterIterator
                        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()) {
index 71ad2fc9ee3a2a9ab243cb09d7fe95616f3e1694..2924b909666ffbfb5a4e6e7f2def74266b6b2807 100755 (executable)
@@ -65,6 +65,9 @@ typedef enum {
        RIT_CHILD_FIRST = 2
 } RecursiveIteratorMode;
 
+#define RIT_MODE_MASK       0x000000FF
+#define RIT_CATCH_GET_CHILD 0x00000100
+
 typedef enum {
        RS_NEXT  = 0,
        RS_TEST  = 1,
@@ -85,6 +88,7 @@ typedef struct _spl_recursive_it_object {
        spl_sub_iterator         *iterators;
        int                      level;
        RecursiveIteratorMode    mode;
+       int                      flags;
        zend_function            *callHasChildren;
        zend_function            *callGetChildren;
        zend_function            *beginChildren;
@@ -222,6 +226,20 @@ next_step:
                                } 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) {
@@ -344,7 +362,8 @@ SPL_METHOD(RecursiveIteratorIterator, __construct)
        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) {
@@ -1308,8 +1327,7 @@ static INLINE void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
                        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);
                                        }
@@ -1914,9 +1932,10 @@ PHP_MINIT_FUNCTION(spl_iterators)
        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);