From: Gustavo André dos Santos Lopes Date: Sun, 27 Mar 2011 04:21:06 +0000 (+0000) Subject: - Fixed bug #54384: Several SPL classes crash when parent constructor is X-Git-Tag: php-5.4.0alpha1~191^2~108 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c2fe893985f619fdb4f8d17c16405e8ce7926db5;p=php - Fixed bug #54384: Several SPL classes crash when parent constructor is 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). --- diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 10b3e43fff..cd9a548d8f 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -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) diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h index bafaf53d41..ee6482548a 100755 --- a/ext/spl/php_spl.h +++ b/ext/spl/php_spl.h @@ -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 */ /* diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index ab7bfe5142..b2220fee1b 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -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; } /* }}} */ diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 1766d2a426..1e2c44359c 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -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; diff --git a/ext/spl/tests/bug41828.phpt b/ext/spl/tests/bug41828.phpt index 6053e0e446..41a22c1370 100644 --- a/ext/spl/tests/bug41828.phpt +++ b/ext/spl/tests/bug41828.phpt @@ -18,4 +18,8 @@ echo $foo->bar(); ==DONE== --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 diff --git a/ext/spl/tests/bug54281.phpt b/ext/spl/tests/bug54281.phpt index d42d9e585d..b1231a8f8b 100644 --- a/ext/spl/tests/bug54281.phpt +++ b/ext/spl/tests/bug54281.phpt @@ -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 index 0000000000..92b9bfea64 --- /dev/null +++ b/ext/spl/tests/bug54384.phpt @@ -0,0 +1,204 @@ +--TEST-- +Bug #54384: Several SPL classes crash when the parent constructor is not called +--FILE-- +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) diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt index 458f071b76..90a9710a58 100755 --- a/ext/spl/tests/iterator_031.phpt +++ b/ext/spl/tests/iterator_031.phpt @@ -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