]> granicus.if.org Git - php/commitdiff
- Fixed bug #54384: Several SPL classes crash when parent constructor is
authorGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 27 Mar 2011 04:21:06 +0000 (04:21 +0000)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 27 Mar 2011 04:21:06 +0000 (04:21 +0000)
  not called.
#Merge to 5.3 pending (slight BC break on AppendIterator, as it's no
#longer possible to defer the call to the parent constructor until
#after the constructor is performed).
#Bugs fixed in an atypical way for SPL. The parent constructor call
#check is performed at construction time by using a wrapper constructor
#instead of a check on the beginning of each instance method.
#Perhaps this should be uniformized in trunk; this method was mainly
#applied only to the ones crashing, except a few iterators (at least
#AppendIterator and RecursiveIteratorIterator).

ext/spl/php_spl.c
ext/spl/php_spl.h
ext/spl/spl_directory.c
ext/spl/spl_iterators.c
ext/spl/tests/bug41828.phpt
ext/spl/tests/bug54281.phpt
ext/spl/tests/bug54384.phpt [new file with mode: 0644]
ext/spl/tests/iterator_031.phpt

index 10b3e43fff5485220a94932c8f2fe6ebd5fd187f..cd9a548d8fbcce468d222096a09077d6abe0d58c 100755 (executable)
@@ -51,14 +51,30 @@ ZEND_DECLARE_MODULE_GLOBALS(spl)
 
 #define SPL_DEFAULT_FILE_EXTENSIONS ".inc,.php"
 
+static void construction_wrapper(INTERNAL_FUNCTION_PARAMETERS);
+
 /* {{{ PHP_GINIT_FUNCTION
  */
 static PHP_GINIT_FUNCTION(spl)
 {
+       zend_function *cwf = &spl_globals->constr_wrapper_fun;
        spl_globals->autoload_extensions     = NULL;
        spl_globals->autoload_extensions_len = 0;
        spl_globals->autoload_functions      = NULL;
        spl_globals->autoload_running        = 0;
+       spl_globals->validating_fun                      = NULL;
+       
+       cwf->type                                                        = ZEND_INTERNAL_FUNCTION;
+       cwf->common.function_name                        = "internal_construction_wrapper";
+       cwf->common.scope                                        = NULL; /* to be filled */
+       cwf->common.fn_flags                             = ZEND_ACC_PRIVATE;
+       cwf->common.prototype                            = NULL;
+       cwf->common.num_args                             = 0; /* not necessarily true but not enforced */
+       cwf->common.required_num_args            = 0;
+       cwf->common.arg_info                             = NULL;
+       
+       cwf->internal_function.handler           = construction_wrapper;
+       cwf->internal_function.module            = &spl_module_entry;
 }
 /* }}} */
 
@@ -776,6 +792,75 @@ int spl_build_class_list_string(zval **entry, char **list TSRMLS_DC) /* {{{ */
        return ZEND_HASH_APPLY_KEEP;
 } /* }}} */
 
+zend_function *php_spl_get_constructor_helper(zval *object, int (*validating_fun)(void *object_data TSRMLS_DC) TSRMLS_DC) /* {{{ */
+{
+       if (Z_OBJCE_P(object)->type == ZEND_INTERNAL_CLASS) {
+               return std_object_handlers.get_constructor(object TSRMLS_CC);
+       } else {
+               SPL_G(validating_fun) = validating_fun;
+               SPL_G(constr_wrapper_fun).common.scope = Z_OBJCE_P(object);
+               return &SPL_G(constr_wrapper_fun);
+       }
+}
+/* }}} */
+
+static void construction_wrapper(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
+{
+       zval                              *this = getThis();
+       void                              *object_data;
+       zend_class_entry          *this_ce;
+       zend_function             *zf;
+       zend_fcall_info           fci = {0};
+       zend_fcall_info_cache fci_cache = {0};
+       zval *retval_ptr          = NULL;
+       
+       object_data = zend_object_store_get_object(this TSRMLS_CC);
+       zf                      = zend_get_std_object_handlers()->get_constructor(this TSRMLS_CC);
+       this_ce         = Z_OBJCE_P(this);
+
+       fci.size                                        = sizeof(fci);
+       fci.function_table                      = &this_ce->function_table;
+       /* fci.function_name = ; not necessary */
+       /* fci.symbol_table = ; not necessary */
+       fci.retval_ptr_ptr                      = &retval_ptr;
+       fci.param_count                         = ZEND_NUM_ARGS();
+       if (fci.param_count > 0) {
+               fci.params                              = emalloc(fci.param_count * sizeof *fci.params);
+               if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), fci.params) == FAILURE) {
+                       zend_throw_exception(NULL, "Unexpected error fetching arguments", 0 TSRMLS_CC);
+                       return;
+               }
+       }
+       fci.object_ptr                          = this;
+       fci.no_separation                       = 0;
+
+       fci_cache.initialized           = 1;
+       fci_cache.called_scope          = EG(current_execute_data)->called_scope;
+       fci_cache.calling_scope         = EG(current_execute_data)->current_scope;
+       fci_cache.function_handler      = zf;
+       fci_cache.object_ptr            = this;
+
+       if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == FAILURE) {
+               if (!EG(exception)) {
+                       zend_throw_exception(NULL, "Error calling parent constructor", 0 TSRMLS_CC);
+               }
+               goto cleanup;
+       }
+       if (!EG(exception) && SPL_G(validating_fun)(object_data TSRMLS_CC) == 0)
+               zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC,
+                       "In the constructor of %s, parent::__construct() must be called "
+                       "and its exceptions cannot be cleared", this_ce->name);
+       
+cleanup:
+       if (fci.params != NULL) {
+               efree(fci.params);
+       }
+       if (retval_ptr != NULL) {
+               zval_ptr_dtor(&retval_ptr);
+       }
+}
+/* }}} */
+
 /* {{{ PHP_MINFO(spl)
  */
 PHP_MINFO_FUNCTION(spl)
index bafaf53d41de9a2ee0ae231776796a4333c55524..ee6482548a9194ad9ddfde8ae8596d7512429b1a 100755 (executable)
@@ -63,13 +63,15 @@ PHP_MINFO_FUNCTION(spl);
 
 
 ZEND_BEGIN_MODULE_GLOBALS(spl)
-       char *       autoload_extensions;
-       HashTable *  autoload_functions;
-       int          autoload_running;
-       int          autoload_extensions_len;
-       intptr_t     hash_mask_handle;
-       intptr_t     hash_mask_handlers;
-       int          hash_mask_init;
+       char *                  autoload_extensions;
+       HashTable *             autoload_functions;
+       int                             autoload_running;
+       int                             autoload_extensions_len;
+       intptr_t                hash_mask_handle;
+       intptr_t                hash_mask_handlers;
+       int                             hash_mask_init;
+       zend_function   constr_wrapper_fun;
+       int                             (*validating_fun)(void *object_data TSRMLS_DC);
 ZEND_END_MODULE_GLOBALS(spl)
 
 #ifdef ZTS
@@ -86,6 +88,8 @@ PHP_FUNCTION(class_implements);
 
 PHPAPI void php_spl_object_hash(zval *obj, char* md5str TSRMLS_DC);
 
+zend_function *php_spl_get_constructor_helper(zval *object, int (*validating_fun)(void *object_data TSRMLS_DC) TSRMLS_DC);
+
 #endif /* PHP_SPL_H */
 
 /*
index ab7bfe5142c70e84bee9879b5a36e530fb757f9a..b2220fee1b91988566c672ebbe777d5c0b5dbcf0 100755 (executable)
@@ -48,8 +48,9 @@
 
 /* declare the class handlers */
 static zend_object_handlers spl_filesystem_object_handlers;
+static zend_object_handlers spl_filesystem_object_constru_check_handlers;
 
-/* decalre the class entry */
+/* declare the class entry */
 PHPAPI zend_class_entry *spl_ce_SplFileInfo;
 PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
 PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
@@ -132,7 +133,7 @@ static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */
    - clone
    - new
  */
-static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_type, spl_filesystem_object **obj TSRMLS_DC)
+static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_type, zend_object_handlers *handlers, spl_filesystem_object **obj TSRMLS_DC)
 {
        zend_object_value retval;
        spl_filesystem_object *intern;
@@ -142,13 +143,19 @@ static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_ty
        /* intern->type = SPL_FS_INFO; done by set 0 */
        intern->file_class = spl_ce_SplFileObject;
        intern->info_class = spl_ce_SplFileInfo;
-       if (obj) *obj = intern;
+       if (obj) {
+               *obj = intern;
+       }
 
        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
        object_properties_init(&intern->std, class_type);
 
        retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_filesystem_object_free_storage, NULL TSRMLS_CC);
-       retval.handlers = &spl_filesystem_object_handlers;
+       if (!handlers) {
+               retval.handlers = &spl_filesystem_object_handlers;
+       } else {
+               retval.handlers = handlers;
+       }
        return retval;
 }
 /* }}} */
@@ -157,7 +164,13 @@ static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_ty
 /* See spl_filesystem_object_new_ex */
 static zend_object_value spl_filesystem_object_new(zend_class_entry *class_type TSRMLS_DC)
 {
-       return spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC);
+       return spl_filesystem_object_new_ex(class_type, NULL /* spl_filesystem_object_handlers */, NULL TSRMLS_CC);
+}
+/* }}} */
+
+static zend_object_value spl_filesystem_object_constru_check_new(zend_class_entry *class_type TSRMLS_DC)
+{
+       return spl_filesystem_object_new_ex(class_type, &spl_filesystem_object_constru_check_handlers, NULL TSRMLS_CC);
 }
 /* }}} */
 
@@ -307,7 +320,7 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
        old_object = zend_objects_get_address(zobject TSRMLS_CC);
        source = (spl_filesystem_object*)old_object;
 
-       new_obj_val = spl_filesystem_object_new_ex(old_object->ce, &intern TSRMLS_CC);
+       new_obj_val = spl_filesystem_object_new_ex(old_object->ce, NULL, &intern TSRMLS_CC);
        new_object = &intern->std;
 
        intern->flags = source->flags;
@@ -406,7 +419,7 @@ static spl_filesystem_object * spl_filesystem_object_create_info(spl_filesystem_
 
        zend_update_class_constants(ce TSRMLS_CC);
 
-       return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+       return_value->value.obj = spl_filesystem_object_new_ex(ce, NULL, &intern TSRMLS_CC);
        Z_TYPE_P(return_value) = IS_OBJECT;
 
        if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
@@ -449,7 +462,7 @@ static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_fil
 
                zend_update_class_constants(ce TSRMLS_CC);
 
-               return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+               return_value->value.obj = spl_filesystem_object_new_ex(ce, NULL, &intern TSRMLS_CC);
                Z_TYPE_P(return_value) = IS_OBJECT;
 
                spl_filesystem_object_get_file_name(source TSRMLS_CC);
@@ -470,7 +483,7 @@ static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_fil
 
                zend_update_class_constants(ce TSRMLS_CC);
 
-               return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+               return_value->value.obj = spl_filesystem_object_new_ex(ce, NULL, &intern TSRMLS_CC);
                Z_TYPE_P(return_value) = IS_OBJECT;
        
                spl_filesystem_object_get_file_name(source TSRMLS_CC);
@@ -620,6 +633,27 @@ static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp T
 }
 /* }}} */
 
+static int spl_filesystem_object_constructor_validator(void *object_data TSRMLS_DC) /* {{{ */
+{
+       spl_filesystem_object *fsobj = object_data;
+       
+       /* check if GlobIterator and Spl[Temp]FileObject had their constructor 
+        * and check if everything went smoothly/there was an exception not cleared
+        * or if there was an userspace class that did not call the parent
+        * constructor or cleared its exception */
+       
+       return (fsobj->u.dir.entry.d_name[0] != '\0' /* GlobIterator */ ||
+                       fsobj->orig_path != NULL /* Spl[Temp]FileObject */);
+}
+/* }}} */
+
+static zend_function *spl_filesystem_object_get_constructor(zval *object TSRMLS_DC) /* {{{ */
+{
+       return php_spl_get_constructor_helper(object,
+                       spl_filesystem_object_constructor_validator TSRMLS_CC);
+}
+/* }}} */
+
 #define DIT_CTOR_FLAGS  0x00000001
 #define DIT_CTOR_GLOB   0x00000002
 
@@ -2949,7 +2983,7 @@ PHP_MINIT_FUNCTION(spl_directory)
        REGISTER_SPL_IMPLEMENTS(DirectoryIterator, SeekableIterator);
 
        spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator;
-
+       
        REGISTER_SPL_SUB_CLASS_EX(FilesystemIterator, DirectoryIterator, spl_filesystem_object_new, spl_FilesystemIterator_functions);
 
        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_MODE_MASK",   SPL_FILE_DIR_CURRENT_MODE_MASK);
@@ -2968,13 +3002,18 @@ PHP_MINIT_FUNCTION(spl_directory)
 
        REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions);
        REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator);
+       
+       /* These need the parent constructor call check if extended in userspace.
+        * The previous ones probably don't work very well if */
+       memcpy(&spl_filesystem_object_constru_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
+       spl_filesystem_object_constru_check_handlers.get_constructor = spl_filesystem_object_get_constructor;
 
 #ifdef HAVE_GLOB
-       REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new, spl_GlobIterator_functions);
+       REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_constru_check_new, spl_GlobIterator_functions);
        REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable);
 #endif
 
-       REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new, spl_SplFileObject_functions);
+       REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_constru_check_new, spl_SplFileObject_functions);
        REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator);
        REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator);
 
@@ -2983,7 +3022,7 @@ PHP_MINIT_FUNCTION(spl_directory)
        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY",    SPL_FILE_OBJECT_SKIP_EMPTY);
        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV",      SPL_FILE_OBJECT_READ_CSV);
        
-       REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new, spl_SplTempFileObject_functions);
+       REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_constru_check_new, spl_SplTempFileObject_functions);
        return SUCCESS;
 }
 /* }}} */
index 1766d2a4268f74de67f36eb644f057dc5ffe7b77..1e2c44359cbf9614ad5c543ada3d6a8db0dd50be 100755 (executable)
@@ -848,6 +848,34 @@ static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char
        return function_handler;
 }
 
+static int spl_recursive_it_constructor_validator(void *object_data TSRMLS_DC) /* {{{ */
+{
+       spl_recursive_it_object *sobj = object_data;
+       return (sobj->iterators != NULL);
+}
+/* }}} */
+
+static zend_function *spl_recursive_it_get_constructor(zval *object TSRMLS_DC) /* {{{ */
+{
+       return php_spl_get_constructor_helper(object,
+                       spl_recursive_it_constructor_validator TSRMLS_CC);
+}
+/* }}} */
+
+static int spl_dual_it_constructor_validator(void *object_data TSRMLS_DC) /* {{{ */
+{
+       spl_dual_it_object *dobj = object_data;
+       return (dobj->dit_type != DIT_Unknown);
+}
+/* }}} */
+
+static zend_function *spl_dual_it_get_constructor(zval *object TSRMLS_DC) /* {{{ */
+{
+       return php_spl_get_constructor_helper(object,
+                       spl_dual_it_constructor_validator TSRMLS_CC);
+}
+/* }}} */
+
 /* {{{ spl_RecursiveIteratorIterator_dtor */
 static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
 {
@@ -1321,15 +1349,6 @@ int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 }
 #endif
 
-#define SPL_CHECK_CTOR(intern, classname) \
-       if (intern->dit_type == DIT_Unknown) { \
-               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \
-                               (spl_ce_##classname)->name, (spl_ce_##classname)->name); \
-               return; \
-       }
-
-#define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
-
 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
 
 static inline int spl_cit_check_flags(int flags)
@@ -3166,8 +3185,6 @@ SPL_METHOD(AppendIterator, append)
        zval *it;
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
-       
-       APPENDIT_CHECK_CTOR(intern);
 
        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
                return;
@@ -3244,8 +3261,7 @@ SPL_METHOD(AppendIterator, getIteratorIndex)
        }
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
-
-       APPENDIT_CHECK_CTOR(intern);
+       
        spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
 } /* }}} */
 
@@ -3260,8 +3276,7 @@ SPL_METHOD(AppendIterator, getArrayIterator)
        }
 
        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
-
-       APPENDIT_CHECK_CTOR(intern);
+       
        RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
 } /* }}} */
 
@@ -3491,11 +3506,13 @@ PHP_MINIT_FUNCTION(spl_iterators)
        memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
        spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
        spl_handlers_rec_it_it.clone_obj = NULL;
+       spl_handlers_rec_it_it.get_constructor = spl_recursive_it_get_constructor;
 
        memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
        spl_handlers_dual_it.get_method = spl_dual_it_get_method;
        /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
        spl_handlers_dual_it.clone_obj = NULL;
+       spl_handlers_dual_it.get_constructor = spl_dual_it_get_constructor;
        
        spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
        spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
index 6053e0e4468beed3612c6e2a7f6755e9fb38b682..41a22c1370c8bb3794942fde0db0c1b522b439ce 100644 (file)
@@ -18,4 +18,8 @@ echo $foo->bar();
 ==DONE==
 <?php exit(0); ?>
 --EXPECTF--
-Fatal error: main(): The foo instance wasn't initialized properly in %s on line %d
+Fatal error: Uncaught exception 'LogicException' with message 'In the constructor of foo, parent::__construct() must be called and its exceptions cannot be cleared' in %s:%d
+Stack trace:
+#0 %s(%d): foo->internal_construction_wrapper('This is bar')
+#1 {main}
+  thrown in %s on line %d
index d42d9e585d365abb98eda510a96db0078562c2b0..b1231a8f8b0e7aabdc7dcfa024d86b7f9cf6400a 100644 (file)
@@ -12,4 +12,8 @@ foreach($it as $k=>$v) { }
 
 ?>
 --EXPECTF--
-Fatal error: RecursiveIteratorIterator::rewind(): The RecursiveArrayIteratorIterator instance wasn't initialized properly in %s on line %d
+Fatal error: Uncaught exception 'LogicException' with message 'In the constructor of RecursiveArrayIteratorIterator, parent::__construct() must be called and its exceptions cannot be cleared' in %s:%d
+Stack trace:
+#0 %s(%d): RecursiveArrayIteratorIterator->internal_construction_wrapper(Object(RecursiveArrayIterator), 2)
+#1 {main}
+  thrown in %s on line %d
diff --git a/ext/spl/tests/bug54384.phpt b/ext/spl/tests/bug54384.phpt
new file mode 100644 (file)
index 0000000..92b9bfe
--- /dev/null
@@ -0,0 +1,204 @@
+--TEST--
+Bug #54384: Several SPL classes crash when the parent constructor is not called
+--FILE--
+<?php
+
+function test($f) {
+       try {
+               $f();
+               echo "ran normally (unexpected)\n\n";
+       } catch (LogicException $e) {
+               echo "exception (expected)\n";
+       }
+}
+
+echo "IteratorIterator... ";
+class IteratorIteratorTest extends IteratorIterator {
+    function __construct(){}
+}
+test( function() {
+       $o = new IteratorIteratorTest;
+       $o->rewind();
+} );
+
+echo "FilterIterator... ";
+class FilterIteratorTest extends FilterIterator {
+    function __construct(){}
+    function accept(){}
+}
+test( function() {
+       $o = new FilterIteratorTest;
+       $o->rewind();
+} );
+
+echo "RecursiveFilterIterator... ";
+class RecursiveFilterIteratorTest extends RecursiveFilterIterator {
+    function __construct(){}
+    function accept(){}
+}
+test( function() {
+$o = new RecursiveFilterIteratorTest;
+$o->hasChildren();
+} );
+
+echo "ParentIterator... ";
+class ParentIteratorTest extends ParentIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new ParentIteratorTest;
+$o->accept();
+} );
+
+echo "LimitIterator... ";
+class LimitIteratorTest extends LimitIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new LimitIteratorTest;
+$o->rewind();
+} );
+
+echo "CachingIterator... ";
+class CachingIteratorTest extends CachingIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new CachingIteratorTest;
+$o->rewind();
+} );
+
+echo "RecursiveCachingIterator... ";
+class RecursiveCachingIteratorTest extends RecursiveCachingIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new RecursiveCachingIteratorTest;
+$o->rewind();
+} );
+
+echo "NoRewindIterator... ";
+class NoRewindIteratorTest extends NoRewindIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new NoRewindIteratorTest;
+$o->valid();
+} );
+
+echo "RegexIterator... ";
+class RegexIteratorTest extends RegexIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new RegexIteratorTest;
+$o->rewind();
+} );
+
+echo "RecursiveRegexIterator... ";
+class RecursiveRegexIteratorTest extends RecursiveRegexIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new RecursiveRegexIteratorTest;
+$o->hasChildren();
+} );
+
+echo "GlobIterator... ";
+class GlobIteratorTest extends GlobIterator {
+    function __construct(){}
+}
+test ( function() {
+$o = new GlobIteratorTest;
+$o->count();
+} );
+
+echo "SplFileObject... ";
+class SplFileObjectTest extends SplFileObject {
+    function __construct(){}
+}
+test ( function() {
+$o = new SplFileObjectTest;
+$o->rewind();
+} );
+
+echo "SplTempFileObject... ";
+class SplTempFileObjectTest extends SplTempFileObject {
+    function __construct(){}
+}
+test ( function() {
+$o = new SplTempFileObjectTest;
+$o->rewind();
+} );
+
+
+
+function test2($f) {
+       try {
+               $f();
+               echo "ran normally (expected)\n";
+       } catch (LogicException $e) {
+               echo "exception (unexpected)\n\n";
+       }
+}
+
+echo "SplFileInfo... ";
+class SplFileInfoTest extends SplFileInfo {
+    function __construct(){}
+}
+test2 ( function() {
+$o = new SplFileInfoTest;
+/* handles with fatal error */
+/* echo $o->getMTime(), " : "; */
+} );
+
+echo "DirectoryIterator... ";
+class DirectoryIteratortest extends DirectoryIterator {
+    function __construct(){}
+}
+test2 ( function() {
+$o = new DirectoryIteratorTest;
+foreach ($o as $a) {
+echo $a,"\n";
+}
+} );
+
+echo "FileSystemIterator... ";
+class FileSystemIteratorTest extends DirectoryIterator {
+    function __construct(){}
+}
+test2 ( function() {
+$o = new FileSystemIteratorTest;
+foreach ($o as $a) {
+echo $a,"\n";
+}
+} );
+
+echo "RecursiveDirectoryIterator... ";
+class RecursiveDirectoryIteratorTest extends RecursiveDirectoryIterator {
+    function __construct(){}
+}
+test2 ( function() {
+$o = new RecursiveDirectoryIteratorTest;
+foreach ($o as $a) {
+echo $a,"\n";
+}
+} );
+--EXPECT--
+IteratorIterator... exception (expected)
+FilterIterator... exception (expected)
+RecursiveFilterIterator... exception (expected)
+ParentIterator... exception (expected)
+LimitIterator... exception (expected)
+CachingIterator... exception (expected)
+RecursiveCachingIterator... exception (expected)
+NoRewindIterator... exception (expected)
+RegexIterator... exception (expected)
+RecursiveRegexIterator... exception (expected)
+GlobIterator... exception (expected)
+SplFileObject... exception (expected)
+SplTempFileObject... exception (expected)
+SplFileInfo... ran normally (expected)
+DirectoryIterator... ran normally (expected)
+FileSystemIterator... ran normally (expected)
+RecursiveDirectoryIterator... ran normally (expected)
index 458f071b76f8a46cadc3872aad981b4124972667..90a9710a58ad03311b546363f37009a28f30165d 100755 (executable)
@@ -19,10 +19,19 @@ foreach($it as $k=>$v)
        echo "$k=>$v\n";
 }
 
+class MyAppendIterator2 extends AppendIterator
+{
+       function __construct()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
 class MyAppendIterator extends AppendIterator
 {
        function __construct()
        {
+               parent::__construct();
                echo __METHOD__ . "\n";
        }
 
@@ -50,24 +59,23 @@ class MyAppendIterator extends AppendIterator
        }
 }
 
-$ap = new MyAppendIterator;
-
 try
 {
-       $ap->append($it);
+       $aperr = new MyAppendIterator2;
+
 }
-catch(BadMethodCallException $e)
+catch(Exception $e)
 {
        echo $e->getMessage() . "\n";
 }
 
-$ap->parent__construct();
+$ap = new MyAppendIterator;
 
 try
 {
        $ap->parent__construct($it);
 }
-catch(BadMethodCallException $e)
+catch(Exception $e)
 {
        echo $e->getMessage() . "\n";
 }
@@ -88,9 +96,9 @@ foreach($ap as $k=>$v)
 MyArrayIterator::rewind
 0=>1
 1=>2
+MyAppendIterator2::__construct
+In the constructor of MyAppendIterator2, parent::__construct() must be called and its exceptions cannot be cleared
 MyAppendIterator::__construct
-MyAppendIterator::append
-Classes derived from AppendIterator must call AppendIterator::__construct()
 AppendIterator::getIterator() must be called exactly once per instance
 MyAppendIterator::append
 MyArrayIterator::rewind