summaryrefslogtreecommitdiff
path: root/ext/spl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/spl')
-rwxr-xr-xext/spl/CREDITS2
-rwxr-xr-xext/spl/README7
-rwxr-xr-xext/spl/TODO4
-rwxr-xr-xext/spl/config.m427
-rw-r--r--ext/spl/config.w327
-rwxr-xr-xext/spl/doxygen.cfg217
-rw-r--r--ext/spl/examples/autoload.inc50
-rw-r--r--ext/spl/examples/cachingrecursiveiterator.inc28
-rw-r--r--ext/spl/examples/callbackfilteriterator.inc122
-rwxr-xr-xext/spl/examples/class_tree.php113
-rwxr-xr-xext/spl/examples/dba_array.php52
-rwxr-xr-xext/spl/examples/dba_dump.php42
-rw-r--r--ext/spl/examples/dbaarray.inc95
-rw-r--r--ext/spl/examples/dbareader.inc96
-rw-r--r--ext/spl/examples/directoryfilterdots.inc45
-rw-r--r--ext/spl/examples/directorygraphiterator.inc34
-rw-r--r--ext/spl/examples/directorytree.inc27
-rwxr-xr-xext/spl/examples/directorytree.php37
-rw-r--r--ext/spl/examples/directorytreeiterator.inc54
-rw-r--r--ext/spl/examples/dualiterator.inc210
-rw-r--r--ext/spl/examples/findfile.inc65
-rwxr-xr-xext/spl/examples/findfile.php33
-rwxr-xr-xext/spl/examples/findregex.php36
-rwxr-xr-xext/spl/examples/ini_groups.php41
-rw-r--r--ext/spl/examples/inigroups.inc54
-rw-r--r--ext/spl/examples/keyfilter.inc64
-rwxr-xr-xext/spl/examples/nocvsdir.php55
-rwxr-xr-xext/spl/examples/phar_from_dir.php50
-rw-r--r--ext/spl/examples/recursivecomparedualiterator.inc69
-rw-r--r--ext/spl/examples/recursivedualiterator.inc72
-rw-r--r--ext/spl/examples/regexfindfile.inc40
-rw-r--r--ext/spl/examples/searchiterator.inc58
-rw-r--r--ext/spl/examples/tests/dualiterator_001.phpt48
-rw-r--r--ext/spl/examples/tests/examples.inc23
-rwxr-xr-xext/spl/examples/tree.php40
-rw-r--r--ext/spl/internal/appenditerator.inc122
-rw-r--r--ext/spl/internal/cachingiterator.inc157
-rw-r--r--ext/spl/internal/emptyiterator.inc62
-rw-r--r--ext/spl/internal/filteriterator.inc127
-rw-r--r--ext/spl/internal/infiniteiterator.inc48
-rw-r--r--ext/spl/internal/iteratoriterator.inc121
-rw-r--r--ext/spl/internal/limititerator.inc134
-rw-r--r--ext/spl/internal/multipleiterator.inc223
-rw-r--r--ext/spl/internal/norewinditerator.inc28
-rw-r--r--ext/spl/internal/outeriterator.inc25
-rw-r--r--ext/spl/internal/parentiterator.inc32
-rw-r--r--ext/spl/internal/recursivearrayiterator.inc59
-rw-r--r--ext/spl/internal/recursivecachingiterator.inc99
-rw-r--r--ext/spl/internal/recursivefilteriterator.inc62
-rw-r--r--ext/spl/internal/recursiveiterator.inc30
-rw-r--r--ext/spl/internal/recursiveiteratoriterator.inc237
-rw-r--r--ext/spl/internal/recursiveregexiterator.inc61
-rw-r--r--ext/spl/internal/recursivetreeiterator.inc132
-rw-r--r--ext/spl/internal/regexiterator.inc170
-rw-r--r--ext/spl/internal/seekableiterator.inc48
-rw-r--r--ext/spl/internal/spldoublylinkedlist.inc277
-rw-r--r--ext/spl/internal/splfileobject.inc377
-rw-r--r--ext/spl/internal/splobjectstorage.inc188
-rw-r--r--ext/spl/internal/splqueue.inc71
-rw-r--r--ext/spl/internal/splstack.inc48
-rwxr-xr-xext/spl/package.xml75
-rw-r--r--ext/spl/php_spl.c1001
-rw-r--r--ext/spl/php_spl.h99
-rwxr-xr-xext/spl/spl.php1163
-rw-r--r--ext/spl/spl_array.c1995
-rw-r--r--ext/spl/spl_array.h46
-rw-r--r--ext/spl/spl_directory.c3068
-rw-r--r--ext/spl/spl_directory.h149
-rw-r--r--ext/spl/spl_dllist.c1376
-rw-r--r--ext/spl/spl_dllist.h42
-rw-r--r--ext/spl/spl_engine.c70
-rw-r--r--ext/spl/spl_engine.h61
-rw-r--r--ext/spl/spl_exceptions.c81
-rw-r--r--ext/spl/spl_exceptions.h53
-rw-r--r--ext/spl/spl_fixedarray.c1140
-rw-r--r--ext/spl/spl_fixedarray.h38
-rw-r--r--ext/spl/spl_functions.c153
-rw-r--r--ext/spl/spl_functions.h91
-rw-r--r--ext/spl/spl_heap.c1262
-rw-r--r--ext/spl/spl_heap.h44
-rw-r--r--ext/spl/spl_iterators.c3774
-rw-r--r--ext/spl/spl_iterators.h186
-rw-r--r--ext/spl/spl_observer.c1341
-rw-r--r--ext/spl/spl_observer.h43
-rw-r--r--ext/spl/tests/ArrayObject_unserialize_empty_string.phpt16
-rw-r--r--ext/spl/tests/CallbackFilterIteratorTest-002.phpt50
-rw-r--r--ext/spl/tests/CallbackFilterIteratorTest.phpt133
-rw-r--r--ext/spl/tests/DirectoryIterator_by_reference.phpt14
-rw-r--r--ext/spl/tests/DirectoryIterator_empty_constructor.phpt15
-rw-r--r--ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt23
-rw-r--r--ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt23
-rw-r--r--ext/spl/tests/DirectoryIterator_getExtension_basic.phpt57
-rw-r--r--ext/spl/tests/DirectoryIterator_getGroup_basic.phpt29
-rw-r--r--ext/spl/tests/DirectoryIterator_getInode_basic.phpt29
-rw-r--r--ext/spl/tests/DirectoryIterator_getInode_error.phpt28
-rw-r--r--ext/spl/tests/DirectoryIterator_getOwner_basic.phpt29
-rw-r--r--ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt138
-rw-r--r--ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt50
-rw-r--r--ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt56
-rw-r--r--ext/spl/tests/SplArray_fromArray.phpt17
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_count.phpt12
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt11
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_current.phpt11
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_current_empty.phpt13
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_debug-info.phpt29
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt12
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt12
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt13
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt20
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt19
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt23
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt31
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt15
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt18
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt18
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt27
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt23
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt23
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt15
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_pop_params.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt13
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_serialization.phpt67
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt11
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt14
-rw-r--r--ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt13
-rw-r--r--ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt25
-rw-r--r--ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt17
-rw-r--r--ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt25
-rw-r--r--ext/spl/tests/SplFileInfo_001.phpt11
-rw-r--r--ext/spl/tests/SplFileInfo_getExtension_basic.phpt31
-rw-r--r--ext/spl/tests/SplFileInfo_getGroup_basic.phpt26
-rw-r--r--ext/spl/tests/SplFileInfo_getGroup_error.phpt28
-rw-r--r--ext/spl/tests/SplFileInfo_getInode_basic.phpt30
-rw-r--r--ext/spl/tests/SplFileInfo_getInode_error.phpt28
-rw-r--r--ext/spl/tests/SplFileInfo_getOwner_basic.phpt26
-rw-r--r--ext/spl/tests/SplFileInfo_getOwner_error.phpt28
-rw-r--r--ext/spl/tests/SplFileInfo_getPerms_basic.phpt30
-rw-r--r--ext/spl/tests/SplFileInfo_getPerms_error.phpt28
-rw-r--r--ext/spl/tests/SplFileObject_current_basic.phpt18
-rw-r--r--ext/spl/tests/SplFileObject_current_error001.phpt19
-rw-r--r--ext/spl/tests/SplFileObject_current_variation001.phpt21
-rw-r--r--ext/spl/tests/SplFileObject_fflush_basic_001.phpt38
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_basic.phpt31
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt31
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt23
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt31
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt23
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt24
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt24
-rw-r--r--ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt18
-rw-r--r--ext/spl/tests/SplFileObject_fpassthru_basic.phpt13
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv.phpt106
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_002.phpt42
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_error.phpt35
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation1.phpt826
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation10.phpt327
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation11.phpt826
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation12.phpt827
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation13.phpt29
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation14.phpt29
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation5.phpt826
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation6.phpt829
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation7.phpt829
-rw-r--r--ext/spl/tests/SplFileObject_fputcsv_variation8.phpt829
-rw-r--r--ext/spl/tests/SplFileObject_fscanf_basic.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_fseek_error_001.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_ftruncate_error_001.phpt32
-rw-r--r--ext/spl/tests/SplFileObject_fwrite_error_001.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_fwrite_variation_001.phpt21
-rw-r--r--ext/spl/tests/SplFileObject_fwrite_variation_002.phpt21
-rw-r--r--ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt15
-rw-r--r--ext/spl/tests/SplFileObject_getchildren_basic.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_getchildren_error001.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_getflags_basic.phpt22
-rw-r--r--ext/spl/tests/SplFileObject_getflags_error001.phpt26
-rw-r--r--ext/spl/tests/SplFileObject_getflags_error002.phpt21
-rw-r--r--ext/spl/tests/SplFileObject_getflags_variation001.phpt29
-rw-r--r--ext/spl/tests/SplFileObject_haschildren_basic.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_haschildren_error001.phpt12
-rw-r--r--ext/spl/tests/SplFileObject_key_basic.phpt19
-rw-r--r--ext/spl/tests/SplFileObject_key_error001.phpt22
-rw-r--r--ext/spl/tests/SplFileObject_key_error002.phpt22
-rw-r--r--ext/spl/tests/SplFileObject_key_error003.phpt15
-rw-r--r--ext/spl/tests/SplFileObject_next_basic.phpt22
-rw-r--r--ext/spl/tests/SplFileObject_next_variation001.phpt24
-rw-r--r--ext/spl/tests/SplFileObject_next_variation002.phpt30
-rw-r--r--ext/spl/tests/SplFileObject_rewind_basic.phpt21
-rw-r--r--ext/spl/tests/SplFileObject_rewind_error001.phpt18
-rw-r--r--ext/spl/tests/SplFileObject_rewind_variation001.phpt28
-rw-r--r--ext/spl/tests/SplFileObject_seek_basic.phpt19
-rw-r--r--ext/spl/tests/SplFileObject_seek_error002.phpt18
-rw-r--r--ext/spl/tests/SplFileObject_seek_error_001.phpt19
-rw-r--r--ext/spl/tests/SplFileObject_setCsvControl_basic.phpt30
-rw-r--r--ext/spl/tests/SplFileObject_setCsvControl_error001.phpt24
-rw-r--r--ext/spl/tests/SplFileObject_setCsvControl_error002.phpt24
-rw-r--r--ext/spl/tests/SplFileObject_setCsvControl_error003.phpt26
-rw-r--r--ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt30
-rw-r--r--ext/spl/tests/SplFileObject_testinput.csv5
-rw-r--r--ext/spl/tests/SplFixedArray__construct_param_array.phpt12
-rw-r--r--ext/spl/tests/SplFixedArray__construct_param_float.phpt14
-rw-r--r--ext/spl/tests/SplFixedArray__construct_param_null.phpt16
-rw-r--r--ext/spl/tests/SplFixedArray__construct_param_string.phpt12
-rw-r--r--ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt13
-rw-r--r--ext/spl/tests/SplFixedArray_count_checkParams.phpt16
-rw-r--r--ext/spl/tests/SplFixedArray_count_param_int.phpt11
-rw-r--r--ext/spl/tests/SplFixedArray_current_param.phpt24
-rw-r--r--ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt10
-rw-r--r--ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt10
-rw-r--r--ext/spl/tests/SplFixedArray_fromarray_indexes.phpt22
-rw-r--r--ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt21
-rw-r--r--ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt10
-rw-r--r--ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt17
-rw-r--r--ext/spl/tests/SplFixedArray_getSize_pass_param.phpt12
-rw-r--r--ext/spl/tests/SplFixedArray_key_param.phpt24
-rw-r--r--ext/spl/tests/SplFixedArray_key_setsize.phpt20
-rw-r--r--ext/spl/tests/SplFixedArray_next_param.phpt18
-rw-r--r--ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt13
-rw-r--r--ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt16
-rw-r--r--ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt15
-rw-r--r--ext/spl/tests/SplFixedArray_offsetUnset_string.phpt33
-rw-r--r--ext/spl/tests/SplFixedArray_rewind_param.phpt18
-rw-r--r--ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt22
-rw-r--r--ext/spl/tests/SplFixedArray_setSize_param_array.phpt18
-rw-r--r--ext/spl/tests/SplFixedArray_setSize_param_float.phpt19
-rw-r--r--ext/spl/tests/SplFixedArray_setSize_param_null.phpt13
-rw-r--r--ext/spl/tests/SplFixedArray_setSize_reduce.phpt22
-rw-r--r--ext/spl/tests/SplFixedArray_setsize_001.phpt22
-rw-r--r--ext/spl/tests/SplFixedArray_setsize_grow.phpt30
-rw-r--r--ext/spl/tests/SplFixedArray_setsize_shrink.phpt28
-rw-r--r--ext/spl/tests/SplFixedArray_toArray_with-params.phpt19
-rw-r--r--ext/spl/tests/SplHeap_count_invalid_parameter.phpt47
-rw-r--r--ext/spl/tests/SplHeap_extract_invalid_parameter.phpt47
-rw-r--r--ext/spl/tests/SplHeap_insert_invalid_parameter.phpt16
-rw-r--r--ext/spl/tests/SplHeap_isEmpty.phpt15
-rw-r--r--ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt47
-rw-r--r--ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt43
-rw-r--r--ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt20
-rw-r--r--ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt43
-rw-r--r--ext/spl/tests/SplObjectStorage_current_empty_storage.phpt15
-rw-r--r--ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt43
-rw-r--r--ext/spl/tests/SplObjectStorage_getHash.phpt60
-rw-r--r--ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt15
-rw-r--r--ext/spl/tests/SplObjectStorage_offsetGet.phpt17
-rw-r--r--ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt45
-rw-r--r--ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt20
-rw-r--r--ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt27
-rw-r--r--ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt44
-rw-r--r--ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt43
-rw-r--r--ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt15
-rw-r--r--ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt16
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_bad.phpt45
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt27
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt34
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt19
-rw-r--r--ext/spl/tests/SplObjectStorage_unserialize_nested.phpt47
-rw-r--r--ext/spl/tests/SplObjectStorage_var_dump.phpt23
-rw-r--r--ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt47
-rw-r--r--ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt16
-rw-r--r--ext/spl/tests/SplQueue_setIteratorMode.phpt15
-rw-r--r--ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt19
-rw-r--r--ext/spl/tests/SplStack_setIteratorMode.phpt15
-rw-r--r--ext/spl/tests/SplTempFileObject_constructor_basic.phpt19
-rw-r--r--ext/spl/tests/SplTempFileObject_constructor_error.phpt12
-rw-r--r--ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt19
-rw-r--r--ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt19
-rw-r--r--ext/spl/tests/arrayObject___construct_basic1.phpt52
-rw-r--r--ext/spl/tests/arrayObject___construct_basic2.phpt104
-rw-r--r--ext/spl/tests/arrayObject___construct_basic3.phpt104
-rw-r--r--ext/spl/tests/arrayObject___construct_basic4.phpt106
-rw-r--r--ext/spl/tests/arrayObject___construct_basic5.phpt106
-rw-r--r--ext/spl/tests/arrayObject___construct_basic6.phpt80
-rw-r--r--ext/spl/tests/arrayObject___construct_error1.phpt25
-rw-r--r--ext/spl/tests/arrayObject___construct_error2.phpt22
-rw-r--r--ext/spl/tests/arrayObject_asort_basic1.phpt64
-rw-r--r--ext/spl/tests/arrayObject_asort_basic2.phpt52
-rw-r--r--ext/spl/tests/arrayObject_clone_basic1.phpt48
-rw-r--r--ext/spl/tests/arrayObject_clone_basic2.phpt46
-rw-r--r--ext/spl/tests/arrayObject_clone_basic3.phpt80
-rw-r--r--ext/spl/tests/arrayObject_count_basic1.phpt84
-rw-r--r--ext/spl/tests/arrayObject_exchangeArray_basic1.phpt40
-rw-r--r--ext/spl/tests/arrayObject_exchangeArray_basic2.phpt97
-rw-r--r--ext/spl/tests/arrayObject_exchangeArray_basic3.phpt128
-rw-r--r--ext/spl/tests/arrayObject_getFlags_basic1.phpt25
-rw-r--r--ext/spl/tests/arrayObject_getFlags_basic2.phpt24
-rw-r--r--ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt116
-rw-r--r--ext/spl/tests/arrayObject_ksort_basic1.phpt67
-rw-r--r--ext/spl/tests/arrayObject_ksort_basic2.phpt52
-rw-r--r--ext/spl/tests/arrayObject_magicMethods1.phpt195
-rw-r--r--ext/spl/tests/arrayObject_magicMethods2.phpt197
-rw-r--r--ext/spl/tests/arrayObject_magicMethods3.phpt195
-rw-r--r--ext/spl/tests/arrayObject_magicMethods4.phpt206
-rw-r--r--ext/spl/tests/arrayObject_magicMethods5.phpt206
-rw-r--r--ext/spl/tests/arrayObject_magicMethods6.phpt206
-rw-r--r--ext/spl/tests/arrayObject_natcasesort_basic1.phpt56
-rw-r--r--ext/spl/tests/arrayObject_natsort_basic1.phpt57
-rw-r--r--ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt10
-rw-r--r--ext/spl/tests/arrayObject_setFlags_basic1.phpt51
-rw-r--r--ext/spl/tests/arrayObject_setFlags_basic2.phpt29
-rw-r--r--ext/spl/tests/arrayObject_setIteratorClass_error1.phpt56
-rw-r--r--ext/spl/tests/arrayObject_uasort_basic1.phpt44
-rw-r--r--ext/spl/tests/arrayObject_uasort_error1.phpt30
-rw-r--r--ext/spl/tests/arrayObject_uksort_basic1.phpt47
-rw-r--r--ext/spl/tests/arrayObject_uksort_error1.phpt30
-rw-r--r--ext/spl/tests/array_001.phpt113
-rw-r--r--ext/spl/tests/array_002.phpt41
-rw-r--r--ext/spl/tests/array_003.phpt63
-rw-r--r--ext/spl/tests/array_004.phpt30
-rw-r--r--ext/spl/tests/array_005.phpt91
-rw-r--r--ext/spl/tests/array_006.phpt30
-rw-r--r--ext/spl/tests/array_007.phpt71
-rw-r--r--ext/spl/tests/array_008.phpt31
-rw-r--r--ext/spl/tests/array_009.phpt24
-rw-r--r--ext/spl/tests/array_009a.phpt37
-rw-r--r--ext/spl/tests/array_010.phpt144
-rw-r--r--ext/spl/tests/array_011.phpt35
-rw-r--r--ext/spl/tests/array_012.phpt63
-rw-r--r--ext/spl/tests/array_013.phpt79
-rw-r--r--ext/spl/tests/array_014.phpt59
-rw-r--r--ext/spl/tests/array_015.phpt97
-rw-r--r--ext/spl/tests/array_016.phpt32
-rw-r--r--ext/spl/tests/array_017.phpt817
-rw-r--r--ext/spl/tests/array_018.phptbin0 -> 633 bytes
-rw-r--r--ext/spl/tests/array_019.phpt30
-rw-r--r--ext/spl/tests/array_020.phpt64
-rw-r--r--ext/spl/tests/array_021.phpt31
-rw-r--r--ext/spl/tests/array_022.phpt80
-rw-r--r--ext/spl/tests/array_023.phpt87
-rw-r--r--ext/spl/tests/array_024.phpt17
-rw-r--r--ext/spl/tests/array_025.phpt40
-rw-r--r--ext/spl/tests/array_026.phpt24
-rw-r--r--ext/spl/tests/array_027.phpt18
-rw-r--r--ext/spl/tests/bug28822.phpt16
-rw-r--r--ext/spl/tests/bug31185.phpt61
-rw-r--r--ext/spl/tests/bug31346.phpt19
-rw-r--r--ext/spl/tests/bug31348.phpt15
-rw-r--r--ext/spl/tests/bug31926.phpt16
-rw-r--r--ext/spl/tests/bug32134.phpt48
-rw-r--r--ext/spl/tests/bug32394.phpt17
-rw-r--r--ext/spl/tests/bug33136.phpt80
-rw-r--r--ext/spl/tests/bug34548.phpt38
-rw-r--r--ext/spl/tests/bug36258.phpt19
-rw-r--r--ext/spl/tests/bug36287.phpt32
-rw-r--r--ext/spl/tests/bug36825.phpt31
-rw-r--r--ext/spl/tests/bug36941.phpt46
-rw-r--r--ext/spl/tests/bug37457.phpt80
-rw-r--r--ext/spl/tests/bug38325.phpt9
-rw-r--r--ext/spl/tests/bug38618.phpt105
-rw-r--r--ext/spl/tests/bug40036.phpt32
-rw-r--r--ext/spl/tests/bug40091.phpt43
-rw-r--r--ext/spl/tests/bug40442.phpt12
-rw-r--r--ext/spl/tests/bug40872.phpt30
-rw-r--r--ext/spl/tests/bug41528.phpt37
-rw-r--r--ext/spl/tests/bug41691.phpt29
-rw-r--r--ext/spl/tests/bug41692.phpt64
-rw-r--r--ext/spl/tests/bug41828.phpt21
-rw-r--r--ext/spl/tests/bug42364.phpt24
-rw-r--r--ext/spl/tests/bug42654.phpt158
-rw-r--r--ext/spl/tests/bug42703.phpt41
-rw-r--r--ext/spl/tests/bug44144.phpt27
-rw-r--r--ext/spl/tests/bug44615.phpt32
-rw-r--r--ext/spl/tests/bug45216.phpt22
-rw-r--r--ext/spl/tests/bug45614.phpt56
-rw-r--r--ext/spl/tests/bug45622.phpt51
-rw-r--r--ext/spl/tests/bug45622b.phpt33
-rw-r--r--ext/spl/tests/bug45826.phpt88
-rw-r--r--ext/spl/tests/bug46031.phpt9
-rw-r--r--ext/spl/tests/bug46051.phpt14
-rw-r--r--ext/spl/tests/bug46053.phpt12
-rw-r--r--ext/spl/tests/bug46088.phpt11
-rw-r--r--ext/spl/tests/bug46115.phpt11
-rw-r--r--ext/spl/tests/bug46160.phpt14
-rw-r--r--ext/spl/tests/bug47534.phpt14
-rw-r--r--ext/spl/tests/bug48023.phpt12
-rw-r--r--ext/spl/tests/bug48361.phpt14
-rw-r--r--ext/spl/tests/bug48493.phpt26
-rw-r--r--ext/spl/tests/bug49263.phpt54
-rw-r--r--ext/spl/tests/bug49723.phpt16
-rw-r--r--ext/spl/tests/bug49972.phpt11
-rw-r--r--ext/spl/tests/bug50579.phpt40
-rw-r--r--ext/spl/tests/bug51119.phpt34
-rw-r--r--ext/spl/tests/bug51374.phpt19
-rw-r--r--ext/spl/tests/bug51532.phpt14
-rw-r--r--ext/spl/tests/bug52238.phpt24
-rw-r--r--ext/spl/tests/bug52573.phpt18
-rw-r--r--ext/spl/tests/bug52861.phpt22
-rw-r--r--ext/spl/tests/bug53071.phpt27
-rw-r--r--ext/spl/tests/bug53144.phpt20
-rw-r--r--ext/spl/tests/bug53362.phpt22
-rw-r--r--ext/spl/tests/bug53515.phpt27
-rw-r--r--ext/spl/tests/bug54281.phpt15
-rw-r--r--ext/spl/tests/bug54291.phpt13
-rw-r--r--ext/spl/tests/bug54292.phpt14
-rw-r--r--ext/spl/tests/bug54304.phpt26
-rw-r--r--ext/spl/tests/bug54323.phpt24
-rw-r--r--ext/spl/tests/bug54384.phpt171
-rw-r--r--ext/spl/tests/bug54970.phpt33
-rw-r--r--ext/spl/tests/bug54971.phpt37
-rw-r--r--ext/spl/tests/bug60201.phpt30
-rw-r--r--ext/spl/tests/bug61326.phpt17
-rw-r--r--ext/spl/tests/bug61347.phpt40
-rw-r--r--ext/spl/tests/bug61418.phpt23
-rw-r--r--ext/spl/tests/bug61453.phpt19
-rw-r--r--ext/spl/tests/bug61527.phpt92
-rw-r--r--ext/spl/tests/bug62073.phpt22
-rw-r--r--ext/spl/tests/bug62262.phpt10
-rw-r--r--ext/spl/tests/bug62328.phpt24
-rw-r--r--ext/spl/tests/bug62433.phpt18
-rw-r--r--ext/spl/tests/bug62616.phpt15
-rw-r--r--ext/spl/tests/bug62904.phpt19
-rw-r--r--ext/spl/tests/bug62978.phpt50
-rw-r--r--ext/spl/tests/bug63680.phpt16
-rw-r--r--ext/spl/tests/bug64023.phpt20
-rw-r--r--ext/spl/tests/bug64106.phpt15
-rw-r--r--ext/spl/tests/bug64228.phpt25
-rw-r--r--ext/spl/tests/bug64264.phpt29
-rw-r--r--ext/spl/tests/class_implements_basic.phpt33
-rw-r--r--ext/spl/tests/class_implements_basic2.phpt74
-rw-r--r--ext/spl/tests/class_implements_variation.phpt45
-rw-r--r--ext/spl/tests/class_implements_variation1.phpt221
-rw-r--r--ext/spl/tests/class_implements_variation2.phpt259
-rw-r--r--ext/spl/tests/class_uses_basic.phpt33
-rw-r--r--ext/spl/tests/class_uses_basic2.phpt69
-rw-r--r--ext/spl/tests/class_uses_variation.phpt45
-rw-r--r--ext/spl/tests/class_uses_variation1.phpt221
-rw-r--r--ext/spl/tests/class_uses_variation2.phpt261
-rw-r--r--ext/spl/tests/countable_class_basic1.phpt37
-rw-r--r--ext/spl/tests/countable_count_variation1.phpt68
-rw-r--r--ext/spl/tests/dit_001.phpt28
-rw-r--r--ext/spl/tests/dit_001_noglob.phpt27
-rw-r--r--ext/spl/tests/dit_002.phpt77
-rw-r--r--ext/spl/tests/dit_003.phpt15
-rw-r--r--ext/spl/tests/dit_004.phpt24
-rw-r--r--ext/spl/tests/dit_005.phpt22
-rw-r--r--ext/spl/tests/dit_006.phpt50
-rw-r--r--ext/spl/tests/dllist_001.phpt63
-rw-r--r--ext/spl/tests/dllist_002.phpt60
-rw-r--r--ext/spl/tests/dllist_003.phpt43
-rw-r--r--ext/spl/tests/dllist_004.phpt61
-rw-r--r--ext/spl/tests/dllist_005.phpt61
-rw-r--r--ext/spl/tests/dllist_006.phpt62
-rw-r--r--ext/spl/tests/dllist_007.phpt24
-rw-r--r--ext/spl/tests/dllist_008.phpt21
-rw-r--r--ext/spl/tests/dllist_010.phpt33
-rw-r--r--ext/spl/tests/dllist_011.phpt13
-rw-r--r--ext/spl/tests/dllist_012.phpt21
-rw-r--r--ext/spl/tests/dllist_memleak.phpt24
-rw-r--r--ext/spl/tests/fileobject_001.phpt88
-rwxr-xr-xext/spl/tests/fileobject_001a.txt6
-rwxr-xr-xext/spl/tests/fileobject_001b.txt6
-rw-r--r--ext/spl/tests/fileobject_002.phpt122
-rw-r--r--ext/spl/tests/fileobject_003.phpt114
-rw-r--r--ext/spl/tests/fileobject_004.phpt22
-rw-r--r--ext/spl/tests/fileobject_005.phpt42
-rw-r--r--ext/spl/tests/fileobject_checktype_basic.phpt16
-rw-r--r--ext/spl/tests/fileobject_getbasename_basic.phpt13
-rw-r--r--ext/spl/tests/fileobject_getcurrentline_basic.phpt19
-rw-r--r--ext/spl/tests/fileobject_getfileinfo_basic.phpt44
-rw-r--r--ext/spl/tests/fileobject_getmaxlinelen_basic.phpt15
-rw-r--r--ext/spl/tests/fileobject_getmaxlinelen_error001.phpt14
-rw-r--r--ext/spl/tests/fileobject_getsize_basic.phpt22
-rw-r--r--ext/spl/tests/fileobject_setmaxlinelen_basic.phpt15
-rw-r--r--ext/spl/tests/fileobject_setmaxlinelen_error001.phpt17
-rw-r--r--ext/spl/tests/fileobject_setmaxlinelen_error002.phpt12
-rw-r--r--ext/spl/tests/fileobject_setmaxlinelen_error003.phpt12
-rw-r--r--ext/spl/tests/filesystemiterator_flags.phpt40
-rw-r--r--ext/spl/tests/fixedarray_001.phpt60
-rw-r--r--ext/spl/tests/fixedarray_002.phpt100
-rw-r--r--ext/spl/tests/fixedarray_003.phpt86
-rw-r--r--ext/spl/tests/fixedarray_004.phpt18
-rw-r--r--ext/spl/tests/fixedarray_005.phpt12
-rw-r--r--ext/spl/tests/fixedarray_006.phpt22
-rw-r--r--ext/spl/tests/fixedarray_007.phpt26
-rw-r--r--ext/spl/tests/fixedarray_008.phpt30
-rw-r--r--ext/spl/tests/fixedarray_009.phpt10
-rw-r--r--ext/spl/tests/fixedarray_010.phpt50
-rw-r--r--ext/spl/tests/fixedarray_011.phpt14
-rw-r--r--ext/spl/tests/fixedarray_012.phpt19
-rw-r--r--ext/spl/tests/fixedarray_013.phpt21
-rw-r--r--ext/spl/tests/fixedarray_014.phpt15
-rw-r--r--ext/spl/tests/fixedarray_015.phpt49
-rw-r--r--ext/spl/tests/fixedarray_016.phpt17
-rw-r--r--ext/spl/tests/fixedarray_017.phpt17
-rw-r--r--ext/spl/tests/fixedarray_018.phpt17
-rw-r--r--ext/spl/tests/fixedarray_019.phpt51
-rw-r--r--ext/spl/tests/fixedarray_020.phpt36
-rw-r--r--ext/spl/tests/fixedarray_021.phpt78
-rw-r--r--ext/spl/tests/heap_001.phpt53
-rw-r--r--ext/spl/tests/heap_002.phpt50
-rw-r--r--ext/spl/tests/heap_003.phpt44
-rw-r--r--ext/spl/tests/heap_004.phpt67
-rw-r--r--ext/spl/tests/heap_005.phpt121
-rw-r--r--ext/spl/tests/heap_006.phpt121
-rw-r--r--ext/spl/tests/heap_007.phpt32
-rw-r--r--ext/spl/tests/heap_008.phpt34
-rw-r--r--ext/spl/tests/heap_009.phpt56
-rw-r--r--ext/spl/tests/heap_010.phpt21
-rw-r--r--ext/spl/tests/heap_011.phpt31
-rw-r--r--ext/spl/tests/heap_012.phpt22
-rw-r--r--ext/spl/tests/heap_corruption.phpt62
-rw-r--r--ext/spl/tests/heap_current_variation_001.phpt22
-rw-r--r--ext/spl/tests/heap_isempty_variation_001.phpt16
-rw-r--r--ext/spl/tests/heap_it_current_empty.phpt12
-rw-r--r--ext/spl/tests/heap_top_variation_001.phpt14
-rw-r--r--ext/spl/tests/heap_top_variation_002.phpt31
-rw-r--r--ext/spl/tests/heap_top_variation_003.phpt16
-rw-r--r--ext/spl/tests/iterator_001.phpt171
-rw-r--r--ext/spl/tests/iterator_002.phpt55
-rw-r--r--ext/spl/tests/iterator_003.phpt95
-rw-r--r--ext/spl/tests/iterator_004.phpt142
-rw-r--r--ext/spl/tests/iterator_005.phpt52
-rw-r--r--ext/spl/tests/iterator_006.phpt24
-rw-r--r--ext/spl/tests/iterator_007.phpt166
-rw-r--r--ext/spl/tests/iterator_008.phpt89
-rw-r--r--ext/spl/tests/iterator_009.phpt45
-rw-r--r--ext/spl/tests/iterator_010.phpt18
-rw-r--r--ext/spl/tests/iterator_011.phpt51
-rw-r--r--ext/spl/tests/iterator_012.phpt33
-rw-r--r--ext/spl/tests/iterator_013.phpt66
-rw-r--r--ext/spl/tests/iterator_014.phpt138
-rw-r--r--ext/spl/tests/iterator_015.phpt62
-rw-r--r--ext/spl/tests/iterator_016.phpt76
-rw-r--r--ext/spl/tests/iterator_017.phpt18
-rw-r--r--ext/spl/tests/iterator_018.phpt51
-rw-r--r--ext/spl/tests/iterator_019.phpt33
-rw-r--r--ext/spl/tests/iterator_020.phpt66
-rw-r--r--ext/spl/tests/iterator_021.phpt180
-rw-r--r--ext/spl/tests/iterator_022.phpt186
-rw-r--r--ext/spl/tests/iterator_023.phpt193
-rw-r--r--ext/spl/tests/iterator_024.phpt49
-rw-r--r--ext/spl/tests/iterator_025.phpt92
-rw-r--r--ext/spl/tests/iterator_026.phpt38
-rw-r--r--ext/spl/tests/iterator_027.phpt83
-rw-r--r--ext/spl/tests/iterator_028.phpt112
-rw-r--r--ext/spl/tests/iterator_029.phpt38
-rw-r--r--ext/spl/tests/iterator_030.phpt44
-rw-r--r--ext/spl/tests/iterator_031.phpt116
-rw-r--r--ext/spl/tests/iterator_032.phpt50
-rw-r--r--ext/spl/tests/iterator_033.phpt44
-rw-r--r--ext/spl/tests/iterator_034.phpt188
-rw-r--r--ext/spl/tests/iterator_035.phpt15
-rw-r--r--ext/spl/tests/iterator_036.phpt22
-rw-r--r--ext/spl/tests/iterator_037.phpt131
-rw-r--r--ext/spl/tests/iterator_038.phpt19
-rw-r--r--ext/spl/tests/iterator_039.phpt121
-rw-r--r--ext/spl/tests/iterator_040.phpt47
-rw-r--r--ext/spl/tests/iterator_041.phpt117
-rw-r--r--ext/spl/tests/iterator_041a.phpt107
-rw-r--r--ext/spl/tests/iterator_041b.phpt123
-rw-r--r--ext/spl/tests/iterator_042.phpt123
-rw-r--r--ext/spl/tests/iterator_043.phpt18
-rw-r--r--ext/spl/tests/iterator_044.phpt165
-rw-r--r--ext/spl/tests/iterator_045.phpt169
-rw-r--r--ext/spl/tests/iterator_046.phpt51
-rw-r--r--ext/spl/tests/iterator_047.phpt125
-rw-r--r--ext/spl/tests/iterator_048.phpt36
-rw-r--r--ext/spl/tests/iterator_049.phpt25
-rw-r--r--ext/spl/tests/iterator_049b.phptbin0 -> 633 bytes
-rw-r--r--ext/spl/tests/iterator_050.phpt98
-rw-r--r--ext/spl/tests/iterator_051.phpt96
-rw-r--r--ext/spl/tests/iterator_052.phpt319
-rw-r--r--ext/spl/tests/iterator_053.phpt315
-rw-r--r--ext/spl/tests/iterator_054.phpt87
-rw-r--r--ext/spl/tests/iterator_055.phpt62
-rw-r--r--ext/spl/tests/iterator_056.phpt19
-rw-r--r--ext/spl/tests/iterator_057.phpt21
-rw-r--r--ext/spl/tests/iterator_058.phpt24
-rw-r--r--ext/spl/tests/iterator_059.phpt17
-rw-r--r--ext/spl/tests/iterator_060.phpt17
-rw-r--r--ext/spl/tests/iterator_061.phpt17
-rw-r--r--ext/spl/tests/iterator_062.phpt18
-rw-r--r--ext/spl/tests/iterator_063.phpt17
-rw-r--r--ext/spl/tests/iterator_064.phpt15
-rw-r--r--ext/spl/tests/iterator_065.phpt15
-rw-r--r--ext/spl/tests/iterator_066.phpt15
-rw-r--r--ext/spl/tests/iterator_067.phpt16
-rw-r--r--ext/spl/tests/iterator_068.phpt34
-rw-r--r--ext/spl/tests/iterator_069.phpt17
-rw-r--r--ext/spl/tests/iterator_070.phpt20
-rw-r--r--ext/spl/tests/iterator_071.phpt32
-rw-r--r--ext/spl/tests/iterator_count.phpt26
-rw-r--r--ext/spl/tests/iterator_to_array.phpt25
-rw-r--r--ext/spl/tests/limititerator_seek.phpt18
-rw-r--r--ext/spl/tests/multiple_iterator_001.phpt345
-rw-r--r--ext/spl/tests/observer_001.phpt116
-rw-r--r--ext/spl/tests/observer_002.phpt199
-rw-r--r--ext/spl/tests/observer_003.phpt58
-rw-r--r--ext/spl/tests/observer_004.phpt122
-rw-r--r--ext/spl/tests/observer_005.phpt212
-rw-r--r--ext/spl/tests/observer_006.phpt310
-rw-r--r--ext/spl/tests/observer_007.phpt22
-rw-r--r--ext/spl/tests/observer_008.phpt35
-rw-r--r--ext/spl/tests/observer_009.phpt30
-rw-r--r--ext/spl/tests/pqueue_001.phpt96
-rw-r--r--ext/spl/tests/pqueue_002.phpt67
-rw-r--r--ext/spl/tests/pqueue_003.phpt31
-rw-r--r--ext/spl/tests/pqueue_004.phpt54
-rw-r--r--ext/spl/tests/pqueue_compare_basic.phpt19
-rw-r--r--ext/spl/tests/pqueue_compare_error.phpt19
-rw-r--r--ext/spl/tests/pqueue_current_error.phpt12
-rw-r--r--ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt36
-rw-r--r--ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt36
-rw-r--r--ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt42
-rw-r--r--ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt36
-rw-r--r--ext/spl/tests/recursive_tree_iterator_001.phpt102
-rw-r--r--ext/spl/tests/recursive_tree_iterator_002.phpt16
-rw-r--r--ext/spl/tests/recursive_tree_iterator_003.phpt16
-rw-r--r--ext/spl/tests/recursive_tree_iterator_004.phpt43
-rw-r--r--ext/spl/tests/recursive_tree_iterator_005.phpt116
-rw-r--r--ext/spl/tests/recursive_tree_iterator_006.phpt112
-rw-r--r--ext/spl/tests/recursive_tree_iterator_007.phpt33
-rw-r--r--ext/spl/tests/recursive_tree_iterator_008.phpt41
-rw-r--r--ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt32
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt32
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt32
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt20
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt15
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt42
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt20
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt42
-rw-r--r--ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt39
-rw-r--r--ext/spl/tests/regexIterator_flags_basic.phpt24
-rw-r--r--ext/spl/tests/regexIterator_mode_basic.phpt32
-rw-r--r--ext/spl/tests/regexIterator_setMode_error.phpt28
-rw-r--r--ext/spl/tests/regexiterator_getpregflags.phpt33
-rw-r--r--ext/spl/tests/regexiterator_getregex.phpt29
-rw-r--r--ext/spl/tests/regexiterator_setflags_exception.phpt35
-rw-r--r--ext/spl/tests/regexiterator_setpregflags.phpt34
-rw-r--r--ext/spl/tests/regexiterator_setpregflags_exception.phpt36
-rw-r--r--ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt15
-rw-r--r--ext/spl/tests/spl_001.phpt34
-rw-r--r--ext/spl/tests/spl_002.phpt22
-rw-r--r--ext/spl/tests/spl_003.phpt74
-rw-r--r--ext/spl/tests/spl_004.phpt84
-rw-r--r--ext/spl/tests/spl_005.phpt21
-rw-r--r--ext/spl/tests/spl_006.phpt39
-rw-r--r--ext/spl/tests/spl_007.phpt24
-rw-r--r--ext/spl/tests/spl_autoload_001.phpt136
-rw-r--r--ext/spl/tests/spl_autoload_002.phpt70
-rw-r--r--ext/spl/tests/spl_autoload_003.phpt45
-rw-r--r--ext/spl/tests/spl_autoload_004.phpt43
-rw-r--r--ext/spl/tests/spl_autoload_005.phpt55
-rw-r--r--ext/spl/tests/spl_autoload_006.phpt37
-rw-r--r--ext/spl/tests/spl_autoload_007.phpt138
-rw-r--r--ext/spl/tests/spl_autoload_008.phpt129
-rw-r--r--ext/spl/tests/spl_autoload_009.phpt26
-rw-r--r--ext/spl/tests/spl_autoload_010.phpt30
-rw-r--r--ext/spl/tests/spl_autoload_011.phpt31
-rw-r--r--ext/spl/tests/spl_autoload_012.phpt65
-rw-r--r--ext/spl/tests/spl_autoload_013.phpt51
-rw-r--r--ext/spl/tests/spl_autoload_014.phpt47
-rw-r--r--ext/spl/tests/spl_autoload_bug48541.phpt39
-rw-r--r--ext/spl/tests/spl_autoload_call_basic.phpt18
-rw-r--r--ext/spl/tests/spl_caching_iterator_constructor_flags.phpt25
-rw-r--r--ext/spl/tests/spl_cachingiterator___toString_basic.phpt16
-rw-r--r--ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt16
-rw-r--r--ext/spl/tests/spl_classes.phpt13
-rw-r--r--ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt22
-rw-r--r--ext/spl/tests/spl_heap_count_basic.phpt35
-rw-r--r--ext/spl/tests/spl_heap_count_error.phpt12
-rw-r--r--ext/spl/tests/spl_heap_extract_parameter_error.phpt27
-rw-r--r--ext/spl/tests/spl_heap_insert_basic.phpt20
-rw-r--r--ext/spl/tests/spl_heap_is_empty_basic.phpt31
-rw-r--r--ext/spl/tests/spl_heap_isempty.phpt21
-rw-r--r--ext/spl/tests/spl_heap_iteration_error.phpt53
-rw-r--r--ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt15
-rw-r--r--ext/spl/tests/spl_iterator_apply_error.phpt26
-rw-r--r--ext/spl/tests/spl_iterator_apply_error_001.phpt20
-rw-r--r--ext/spl/tests/spl_iterator_caching_count_basic.phpt21
-rw-r--r--ext/spl/tests/spl_iterator_caching_count_error.phpt21
-rw-r--r--ext/spl/tests/spl_iterator_caching_getcache_error.phpt21
-rw-r--r--ext/spl/tests/spl_iterator_getcallchildren.phpt39
-rw-r--r--ext/spl/tests/spl_iterator_iterator_constructor.phpt30
-rw-r--r--ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt16
-rw-r--r--ext/spl/tests/spl_iterator_to_array_basic.phpt13
-rw-r--r--ext/spl/tests/spl_iterator_to_array_error.phpt33
-rw-r--r--ext/spl/tests/spl_limit_iterator_check_limits.phpt37
-rw-r--r--ext/spl/tests/spl_maxheap_compare_basic.phpt22
-rw-r--r--ext/spl/tests/spl_minheap_compare_error.phpt31
-rw-r--r--ext/spl/tests/spl_pq_top_basic.phpt42
-rw-r--r--ext/spl/tests/spl_pq_top_error_args.phpt12
-rw-r--r--ext/spl/tests/spl_pq_top_error_corrupt.phpt38
-rw-r--r--ext/spl/tests/spl_pq_top_error_empty.phpt19
-rw-r--r--ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt31
-rw-r--r--ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt28
-rw-r--r--ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt33
-rw-r--r--ext/spl/tests/splfixedarray_offsetExists_larger.phpt15
-rw-r--r--ext/spl/tests/splpriorityqueue_extract.phpt19
-rw-r--r--ext/spl/tests/splpriorityqueue_setextractflags.phpt17
-rwxr-xr-xext/spl/tests/testclass5
-rw-r--r--ext/spl/tests/testclass.class.inc9
-rw-r--r--ext/spl/tests/testclass.inc5
-rw-r--r--ext/spl/tests/testclass.php.inc5
707 files changed, 56136 insertions, 0 deletions
diff --git a/ext/spl/CREDITS b/ext/spl/CREDITS
new file mode 100755
index 0000000..b1bef82
--- /dev/null
+++ b/ext/spl/CREDITS
@@ -0,0 +1,2 @@
+SPL
+Marcus Boerger, Etienne Kneuss
diff --git a/ext/spl/README b/ext/spl/README
new file mode 100755
index 0000000..b2aeb59
--- /dev/null
+++ b/ext/spl/README
@@ -0,0 +1,7 @@
+This is an extension that aims to implement some efficient data access
+interfaces and classes. You'll find the classes documented using php
+code in the file spl.php or in the corresponding .inc file in the examples
+subdirectory. Based on the internal implementations or the files in the
+examples subdirectory there are also some .php files to experiment with.
+
+For more information look at: http://php.net/~helly/php/ext/spl
diff --git a/ext/spl/TODO b/ext/spl/TODO
new file mode 100755
index 0000000..68b00da
--- /dev/null
+++ b/ext/spl/TODO
@@ -0,0 +1,4 @@
+This is the ToDo of ext/spl:
+
+Implement the classes/interfaces from the .inc files in
+directory examples. \ No newline at end of file
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4
new file mode 100755
index 0000000..a0f0d1a
--- /dev/null
+++ b/ext/spl/config.m4
@@ -0,0 +1,27 @@
+dnl $Id$
+dnl config.m4 for extension SPL
+
+ AC_MSG_CHECKING(whether zend_object_value is packed)
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$INCLUDES -I$abs_srcdir $CPPFLAGS"
+ AC_TRY_RUN([
+#include "Zend/zend_types.h"
+int main(int argc, char **argv) {
+ return ((sizeof(zend_object_handle) + sizeof(zend_object_handlers*)) == sizeof(zend_object_value)) ? 0 : 1;
+}
+ ], [
+ ac_result=1
+ AC_MSG_RESULT(yes)
+ ],[
+ ac_result=0
+ AC_MSG_RESULT(no)
+ ], [
+ ac_result=0
+ AC_MSG_RESULT(no)
+ ])
+ CPPFLAGS=$old_CPPFLAGS
+ AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed])
+ AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
+ PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c, no)
+ PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h])
+ PHP_ADD_EXTENSION_DEP(spl, pcre, true)
diff --git a/ext/spl/config.w32 b/ext/spl/config.w32
new file mode 100644
index 0000000..77cbd20
--- /dev/null
+++ b/ext/spl/config.w32
@@ -0,0 +1,7 @@
+// $Id$
+// vim:ft=javascript
+
+EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c", false /*never shared */);
+AC_DEFINE('HAVE_SPL', 1);
+PHP_SPL="yes";
+PHP_INSTALL_HEADERS("ext/spl", "php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h");
diff --git a/ext/spl/doxygen.cfg b/ext/spl/doxygen.cfg
new file mode 100755
index 0000000..4b71787
--- /dev/null
+++ b/ext/spl/doxygen.cfg
@@ -0,0 +1,217 @@
+# Doxyfile 1.3.9.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = SPL-StandardPHPLibrary
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = NO
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = YES
+INLINE_INHERITED_MEMB = YES
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = YES
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = YES
+TAB_SIZE = 4
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = YES
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = YES
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = spl.php \
+ examples \
+ internal
+FILE_PATTERNS = *.inc \
+ *.php
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 4
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = YES
+CHM_FILE = ../spl.chm
+HHC_LOCATION = hhc.exe
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 1
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = YES
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = YES
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1200
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/ext/spl/examples/autoload.inc b/ext/spl/examples/autoload.inc
new file mode 100644
index 0000000..5871e7d
--- /dev/null
+++ b/ext/spl/examples/autoload.inc
@@ -0,0 +1,50 @@
+<?php
+
+/** @file autoload.inc
+ * @ingroup Examples
+ * @brief function __autoload
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** \internal
+ * Tries to load class $classname from directory $dir.
+ */
+function __load_class($classname, $dir)
+{
+ $file = $dir . '/' . $classname . '.inc';
+ if (file_exists($file))
+ {
+ require_once($file);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @brief Class loader for SPL example classes
+ * @author Marcus Boerger
+ * @version 1.0
+ *
+ * Loads classes automatically from include_path as given by ini or from
+ * current directory of script or include file.
+ */
+function __autoload($classname) {
+ $classname = strtolower($classname);
+ $inc = split(':', ini_get('include_path'));
+ $inc[] = '.';
+ $inc[] = dirname($_SERVER['PATH_TRANSLATED']);
+ foreach($inc as $dir)
+ {
+ if (__load_class($classname, $dir))
+ {
+ fprintf(STDERR, 'Loading class('.$classname.")\n");
+ return;
+ }
+ }
+ fprintf(STDERR, 'Class not found ('.$classname.")\n");
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/cachingrecursiveiterator.inc b/ext/spl/examples/cachingrecursiveiterator.inc
new file mode 100644
index 0000000..4fa6b23
--- /dev/null
+++ b/ext/spl/examples/cachingrecursiveiterator.inc
@@ -0,0 +1,28 @@
+<?php
+
+/** @file cachingrecursiveiterator.inc
+ * @ingroup Examples
+ * @brief class CachingRecursiveIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Compatibility to PHP 5.0
+ * @author Marcus Boerger
+ * @version 1.2
+ * @deprecated
+ *
+ * Class RecursiveCachingIterator was named CachingRecursiveIterator until
+ * PHP 5.0.6.
+ *
+ * @see RecursiveCachingIterator
+ */
+
+class CachingRecursiveIterator extends RecursiveCachingIterator
+{
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/callbackfilteriterator.inc b/ext/spl/examples/callbackfilteriterator.inc
new file mode 100644
index 0000000..5175701
--- /dev/null
+++ b/ext/spl/examples/callbackfilteriterator.inc
@@ -0,0 +1,122 @@
+<?php
+
+/** @file callbackfilteriterator.inc
+ * @ingroup Examples
+ * @brief class CallbackFilterIterator
+ * @author Marcus Boerger
+ * @author Kevin McArthur
+ * @date 2006 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief A non abstract FiletrIterator that uses a callback foreach element
+ * @author Marcus Boerger
+ * @author Kevin McArthur
+ * @version 1.0
+ */
+class CallbackFilterIterator extends FilterIterator
+{
+ const USE_FALSE = 0; /**< mode: accept no elements, no callback */
+ const USE_TRUE = 1; /**< mode: accept all elements, no callback */
+ const USE_VALUE = 2; /**< mode: pass value to callback */
+ const USE_KEY = 3; /**< mode: pass key to callback */
+ const USE_BOTH = 4; /**< mode: pass value and key to callback */
+
+ const REPLACE = 0x00000001; /**< flag: pass key/value by reference */
+
+ private $callback; /**< callback to use */
+ private $mode; /**< mode any of USE_VALUE, USE_KEY, USE_BOTH */
+ private $flags; /**< flags (REPLACE) */
+ private $key; /**< key value */
+ private $current; /**< current value */
+
+ /** Construct a CallbackFilterIterator
+ *
+ * @param it inner iterator (iterator to filter)
+ * @param callback callback function
+ * @param mode any of USE_VALUE, USE_KEY, USE_BOTH
+ * @param flags any of 0, REPLACE
+ */
+ public function __construct(Iterator $it, $callback, $mode = self::USE_VALUE, $flags = 0)
+ {
+ parent::__construct($it);
+ $this->callback = $callback;
+ $this->mode = $mode;
+ $this->flags = $flags;
+ }
+
+ /** Call the filter callback
+ * @return result of filter callback
+ */
+ public function accept()
+ {
+ $this->key = parent::key();
+ $this->current = parent::current();
+
+ switch($this->mode) {
+ default:
+ case self::USE_FALSE;
+ return false;
+ case self::USE_TRUE:
+ return true;
+ case self::USE_VALUE:
+ if($this->flags & self::REPLACE) {
+ return (bool) call_user_func($this->callback, &$this->current);
+ } else {
+ return (bool) call_user_func($this->callback, $this->current);
+ }
+ case self::USE_KEY:
+ if($this->flags & self::REPLACE) {
+ return (bool) call_user_func($this->callback, &$this->key);
+ } else {
+ return (bool) call_user_func($this->callback, $this->key);
+ }
+ case SELF::USE_BOTH:
+ if($this->flags & self::REPLACE) {
+ return (bool) call_user_func($this->callback, &$this->key, &$this->current);
+ } else {
+ return (bool) call_user_func($this->callback, $this->key, $this->current);
+ }
+ }
+ }
+
+ /** @return current key value */
+ function key()
+ {
+ return $this->key;
+ }
+
+ /** @return current value */
+ function current()
+ {
+ return $this->current;
+ }
+
+ /** @return operation mode */
+ function getMode()
+ {
+ return $this->mode;
+ }
+
+ /** @param $mode set new mode, @see mode */
+ function setMode($mode)
+ {
+ $this->mode = $mode;
+ }
+
+ /** @return operation flags */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** @param $flags set new flags, @see flags */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/class_tree.php b/ext/spl/examples/class_tree.php
new file mode 100755
index 0000000..fc021d5
--- /dev/null
+++ b/ext/spl/examples/class_tree.php
@@ -0,0 +1,113 @@
+<?php
+
+/** @file class_tree.php
+ * @brief Class Tree example
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2008
+ * @version 1.1
+ *
+ * Usage: php class_tree.php \<class\>
+ *
+ * Simply specify the root class or interface to tree with parameter \<class\>.
+ */
+
+if ($argc < 2) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <class>
+
+Displays a graphical tree for the given <class>.
+
+<class> The class or interface for which to generate the tree graph.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("RecursiveTreeIterator", false)) require_once("recursivetreeiterator.inc");
+
+/** \brief Collects sub classes for given class or interface
+ */
+class SubClasses extends RecursiveArrayIterator
+{
+ /** @param base base class to collect sub classes for
+ * @param check_interfaces whether we deal with interfaces
+ */
+ function __construct($base, $check_interfaces = false)
+ {
+ foreach(get_declared_classes() as $cname)
+ {
+ $parent = get_parent_class($cname);
+ if (strcasecmp($parent, $base) == 0)
+ {
+ $this->offsetSet($cname, new SubClasses($cname));
+ }
+ if ($check_interfaces)
+ {
+ if ($parent)
+ {
+ $parent_imp = class_implements($parent);
+ }
+ foreach(class_implements($cname) as $iname)
+ {
+ if (strcasecmp($iname, $base) == 0)
+ {
+ if (!$parent || !in_array($iname, $parent_imp))
+ {
+ $this->offsetSet($cname, new SubClasses($cname));
+ }
+ }
+ }
+ }
+ }
+ if ($check_interfaces)
+ {
+ foreach(get_declared_interfaces() as $cname)
+ {
+ foreach(class_implements($cname) as $iname)
+ {
+ if (strcasecmp($iname, $base) == 0)
+ {
+ $this->offsetSet($cname, new SubClasses($cname, true));
+ }
+ }
+ }
+ }
+ $this->uksort('strnatcasecmp');
+ }
+
+ /** @return key() since that is the name we need
+ */
+ function current()
+ {
+ $result = parent::key();
+ $parent = get_parent_class($result);
+ if ($parent)
+ {
+ $interfaces = array_diff(class_implements($result), class_implements($parent));
+ if ($interfaces)
+ {
+ $implements = array();
+ foreach($interfaces as $interface)
+ {
+ $implements = array_merge($implements, class_implements($interface));
+ }
+ $interfaces = array_diff($interfaces, $implements);
+ natcasesort($interfaces);
+ $result .= ' (' . join(', ', $interfaces) . ')';
+ }
+ }
+ return $result;
+ }
+}
+
+$it = new RecursiveTreeIterator(new SubClasses($argv[1], true));
+
+echo $argv[1]."\n";
+foreach($it as $c=>$v)
+{
+ echo "$v\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/dba_array.php b/ext/spl/examples/dba_array.php
new file mode 100755
index 0000000..346ac1f
--- /dev/null
+++ b/ext/spl/examples/dba_array.php
@@ -0,0 +1,52 @@
+<?php
+
+/** @file dba_array.php
+ * @brief Program DBA array utility
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage php dba_array.php \<file\> \<handler\> \<key\> [\<value\>]
+ *
+ * If \<value\> is specified then \<key\> is set to \<value\> in \<file\>.
+ * Else the value of \<key\> is printed only.
+ *
+ * Note: configure with --enable-dba
+ */
+
+if ($argc < 4) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <file> <handler> <key> [<value>]
+
+If <value> is specified then <key> is set to <value> in <file>.
+Else the value of <key> is printed only.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("DbaReader", false)) require_once("dbareader.inc");
+
+try {
+ if ($argc > 2) {
+ $dba = new DbaArray($argv[1], $argv[2]);
+ if ($dba && $argc > 3) {
+ if ($argc > 4) {
+ $dba[$argv[3]] = $argv[4];
+ }
+ var_dump(array('Index' => $argv[3], 'Value' => $dba[$argv[3]]));
+ }
+ unset($dba);
+ }
+ else
+ {
+ echo "Not enough parameters\n";
+ exit(1);
+ }
+}
+catch (exception $err) {
+ var_dump($err);
+ exit(1);
+}
+?> \ No newline at end of file
diff --git a/ext/spl/examples/dba_dump.php b/ext/spl/examples/dba_dump.php
new file mode 100755
index 0000000..2c698d4
--- /dev/null
+++ b/ext/spl/examples/dba_dump.php
@@ -0,0 +1,42 @@
+<?php
+
+/** @file dba_dump.php
+ * @brief Program DBA dump utility
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage: php dba_dump.php \<file\> \<handler\> [\<regex\>]
+ *
+ * Show all groups in the ini file specified by \<file\>.
+ * The regular expression \<regex\> is used to filter the by setting name.
+ *
+ * Note: configure with --enable-dba
+ */
+
+if ($argc < 3) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <file> <handler> [<regex>]
+
+Show all groups in the ini file specified by <file>.
+The regular expression <regex> is used to filter the by setting name.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("DbaReader", false)) require_once("dbareader.inc");
+if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc");
+
+$db = new DbaReader($argv[1], $argv[2]);
+
+if ($argc>3) {
+ $db = new KeyFilter($db, $argv[3]);
+}
+
+foreach($db as $key => $val) {
+ echo "'$key' => '$val'\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/dbaarray.inc b/ext/spl/examples/dbaarray.inc
new file mode 100644
index 0000000..d448ad7
--- /dev/null
+++ b/ext/spl/examples/dbaarray.inc
@@ -0,0 +1,95 @@
+<?php
+
+/** @file dbaarray.inc
+ * @ingroup Examples
+ * @brief class DbaArray
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+if (!class_exists("DbaReader", false)) require_once("dbareader.inc");
+
+/** @ingroup Examples
+ * @brief This implements a DBA Array
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class DbaArray extends DbaReader implements ArrayAccess
+{
+
+ /**
+ * Open database $file with $handler in read only mode.
+ *
+ * @param file Database file to open.
+ * @param handler Handler to use for database access.
+ */
+ function __construct($file, $handler)
+ {
+ $this->db = dba_popen($file, "c", $handler);
+ if (!$this->db) {
+ throw new exception("Databse could not be opened");
+ }
+ }
+
+ /**
+ * Close database.
+ */
+ function __destruct()
+ {
+ parent::__destruct();
+ }
+
+ /**
+ * Read an entry.
+ *
+ * @param $name key to read from
+ * @return value associated with $name
+ */
+ function offsetGet($name)
+ {
+ $data = dba_fetch($name, $this->db);
+ if($data) {
+ //return unserialize($data);
+ return $data;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ /**
+ * Set an entry.
+ *
+ * @param $name key to write to
+ * @param $value value to write
+ */
+ function offsetSet($name, $value)
+ {
+ //dba_replace($name, serialize($value), $this->db);
+ dba_replace($name, $value, $this->db);
+ return $value;
+ }
+
+ /**
+ * @return whether key $name exists.
+ */
+ function offsetExists($name)
+ {
+ return dba_exists($name, $this->db);
+ }
+
+ /**
+ * Delete a key/value pair.
+ *
+ * @param $name key to delete.
+ */
+ function offsetUnset($name)
+ {
+ return dba_delete($name, $this->db);
+ }
+}
+
+?>
diff --git a/ext/spl/examples/dbareader.inc b/ext/spl/examples/dbareader.inc
new file mode 100644
index 0000000..b097912
--- /dev/null
+++ b/ext/spl/examples/dbareader.inc
@@ -0,0 +1,96 @@
+<?php
+
+/** @file dbareader.inc
+ * @ingroup Examples
+ * @brief class DbaReader
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief This implements a DBA Iterator.
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class DbaReader implements Iterator
+{
+
+ protected $db = NULL;
+ private $key = false;
+ private $val = false;
+
+ /**
+ * Open database $file with $handler in read only mode.
+ *
+ * @param file Database file to open.
+ * @param handler Handler to use for database access.
+ */
+ function __construct($file, $handler) {
+ if (!$this->db = dba_open($file, 'r', $handler)) {
+ throw new exception('Could not open file ' . $file);
+ }
+ }
+
+ /**
+ * Close database.
+ */
+ function __destruct() {
+ dba_close($this->db);
+ }
+
+ /**
+ * Rewind to first element.
+ */
+ function rewind() {
+ $this->key = dba_firstkey($this->db);
+ $this->fetch_data();
+ }
+
+ /**
+ * Move to next element.
+ *
+ * @return void
+ */
+ function next() {
+ $this->key = dba_nextkey($this->db);
+ $this->fetch_data();
+ }
+
+ /**
+ * Fetches the current data if $key is valid
+ */
+ private function fetch_data() {
+ if ($this->key !== false) {
+ $this->val = dba_fetch($this->key, $this->db);
+ }
+ }
+
+ /**
+ * @return Current data.
+ */
+ function current() {
+ return $this->val;
+ }
+
+ /**
+ * @return Whether more elements are available.
+ */
+ function valid() {
+ if ($this->db && $this->key !== false) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @return Current key.
+ */
+ function key() {
+ return $this->key;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/directoryfilterdots.inc b/ext/spl/examples/directoryfilterdots.inc
new file mode 100644
index 0000000..37f14b7
--- /dev/null
+++ b/ext/spl/examples/directoryfilterdots.inc
@@ -0,0 +1,45 @@
+<?php
+
+/** @file directoryfilterdots.inc
+ * @ingroup Examples
+ * @brief class DirectoryFilterDots
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief A filtered DirectoryIterator
+ * @author Marcus Boerger
+ * @version 1.2
+ *
+ * This Iterator takes a pathname from which it creates a RecursiveDirectoryIterator
+ * and makes it recursive. Further more it filters the entries '.' and '..'.
+ */
+class DirectoryFilterDots extends RecursiveFilterIterator
+{
+ /** Construct from a path.
+ * @param $path directory to iterate
+ */
+ function __construct($path)
+ {
+ parent::__construct(new RecursiveDirectoryIterator($path));
+ }
+
+ /** @return whether the current entry is neither '.' nor '..'
+ */
+ function accept()
+ {
+ return !$this->getInnerIterator()->isDot();
+ }
+
+ /** @return the current entries path name
+ */
+ function key()
+ {
+ return $this->getInnerIterator()->getPathname();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/directorygraphiterator.inc b/ext/spl/examples/directorygraphiterator.inc
new file mode 100644
index 0000000..5808e3b
--- /dev/null
+++ b/ext/spl/examples/directorygraphiterator.inc
@@ -0,0 +1,34 @@
+<?php
+
+/** @file directorygraphiterator.inc
+ * @ingroup Examples
+ * @brief class DirectoryGraphIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief A tree iterator that only shows directories.
+ * @author Marcus Boerger
+ * @version 1.1
+ */
+class DirectoryGraphIterator extends DirectoryTreeIterator
+{
+ function __construct($path)
+ {
+ RecursiveIteratorIterator::__construct(
+ new RecursiveCachingIterator(
+ new ParentIterator(
+ new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
+ )
+ ),
+ CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
+ ),
+ parent::SELF_FIRST
+ );
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/directorytree.inc b/ext/spl/examples/directorytree.inc
new file mode 100644
index 0000000..7bd9c2c
--- /dev/null
+++ b/ext/spl/examples/directorytree.inc
@@ -0,0 +1,27 @@
+<?php
+
+/** @file directorytree.inc
+ * @ingroup Examples
+ * @brief class DirectoryTree
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief A directory iterator that does not show '.' and '..'.
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class DirectoryTree extends RecursiveIteratorIterator
+{
+ /** Construct from a path.
+ * @param $path directory to iterate
+ */
+ function __construct($path) {
+ parent::__construct(new DirectoryFilterDots($path));
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/directorytree.php b/ext/spl/examples/directorytree.php
new file mode 100755
index 0000000..dc26d6c
--- /dev/null
+++ b/ext/spl/examples/directorytree.php
@@ -0,0 +1,37 @@
+<?php
+
+/** @file directorytree.php
+ * @brief Program Directory tree example
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage: php directorytree.php \<path\> [\<start\> [\<count\>]]
+ *
+ * Simply specify the path to tree with parameter \<path\>.
+ */
+
+if ($argc < 2) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <path>
+
+Displays a graphical directory tree for the given <path>.
+
+<path> The directory for which to generate the directory tree graph.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("DirectoryTreeIterator", false)) require_once("directorytreeiterator.inc");
+
+$length = $argc > 3 ? $argv[3] : -1;
+
+echo $argv[1]."\n";
+foreach(new LimitIterator(new DirectoryTreeIterator($argv[1]), @$argv[2], $length) as $key=>$file) {
+//foreach(new DirectoryTreeIterator($argv[1]) as $file) {
+ echo $file . "\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/directorytreeiterator.inc b/ext/spl/examples/directorytreeiterator.inc
new file mode 100644
index 0000000..8e65d0d
--- /dev/null
+++ b/ext/spl/examples/directorytreeiterator.inc
@@ -0,0 +1,54 @@
+<?php
+
+/** @file directorytreeiterator.inc
+ * @ingroup Examples
+ * @brief class DirectoryTreeIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief DirectoryIterator to generate ASCII graphic directory trees
+ * @author Marcus Boerger
+ * @version 1.1
+ */
+class DirectoryTreeIterator extends RecursiveIteratorIterator
+{
+ /** Construct from a path.
+ * @param $path directory to iterate
+ */
+ function __construct($path)
+ {
+ parent::__construct(
+ new RecursiveCachingIterator(
+ new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
+ ),
+ CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
+ ),
+ parent::SELF_FIRST
+ );
+ }
+
+ /** @return the current element prefixed with ASCII graphics
+ */
+ function current()
+ {
+ $tree = '';
+ for ($l=0; $l < $this->getDepth(); $l++) {
+ $tree .= $this->getSubIterator($l)->hasNext() ? '| ' : ' ';
+ }
+ return $tree . ($this->getSubIterator($l)->hasNext() ? '|-' : '\-')
+ . $this->getSubIterator($l)->__toString();
+ }
+
+ /** Aggregates the inner iterator
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->getSubIterator(), $func), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/dualiterator.inc b/ext/spl/examples/dualiterator.inc
new file mode 100644
index 0000000..4cee203
--- /dev/null
+++ b/ext/spl/examples/dualiterator.inc
@@ -0,0 +1,210 @@
+<?php
+
+/** @file dualiterator.inc
+ * @ingroup Examples
+ * @brief class DualIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Synchronous iteration over two iterators
+ * @author Marcus Boerger
+ * @version 1.3
+ */
+class DualIterator implements Iterator
+{
+ const CURRENT_LHS = 0x01;
+ const CURRENT_RHS = 0x02;
+ const CURRENT_ARRAY = 0x03;
+ const CURRENT_0 = 0x00;
+
+ const KEY_LHS = 0x10;
+ const KEY_RHS = 0x20;
+ const KEY_0 = 0x00;
+
+ const DEFAULT_FLAGS = 0x13;
+
+ private $lhs;
+ private $rhs;
+ private $flags;
+
+ /** construct iterator from two iterators
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param flags iteration flags
+ */
+ function __construct(Iterator $lhs, Iterator $rhs,
+ $flags = 0x13 /*DualIterator::DEFAULT_FLAGS*/)
+ {
+ $this->lhs = $lhs;
+ $this->rhs = $rhs;
+ $this->flags = $flags;
+ }
+
+ /** @return Left Hand Side Iterator
+ */
+ function getLHS()
+ {
+ return $this->lhs;
+ }
+
+ /** @return Right Hand Side Iterator
+ */
+ function getRHS()
+ {
+ return $this->rhs;
+ }
+
+ /** @param flags new flags
+ */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /** @return current flags
+ */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** rewind both inner iterators
+ */
+ function rewind()
+ {
+ $this->lhs->rewind();
+ $this->rhs->rewind();
+ }
+
+ /** @return whether both inner iterators are valid
+ */
+ function valid()
+ {
+ return $this->lhs->valid() && $this->rhs->valid();
+ }
+
+ /** @return current value depending on CURRENT_* flags
+ */
+ function current()
+ {
+ switch($this->flags & 0x0F)
+ {
+ default:
+ case self::CURRENT_ARRAY:
+ return array($this->lhs->current(), $this->rhs->current());
+ case self::CURRENT_LHS:
+ return $this->lhs->current();
+ case self::CURRENT_RHS:
+ return $this->rhs->current();
+ case self::CURRENT_0:
+ return NULL;
+ }
+ }
+
+ /** @return key value depending on KEY_* flags
+ */
+ function key()
+ {
+ switch($this->flags & 0xF0)
+ {
+ default:
+ case self::KEY_LHS:
+ return $this->lhs->key();
+ case self::KEY_RHS:
+ return $this->rhs->key();
+ case self::KEY_0:
+ return NULL;
+ }
+ }
+
+ /** move both inner iterators forward
+ */
+ function next()
+ {
+ $this->lhs->next();
+ $this->rhs->next();
+ }
+
+ /** @return whether both inner iterators are valid and have identical
+ * current and key values or both are non valid.
+ */
+ function areIdentical()
+ {
+ return $this->valid()
+ ? $this->lhs->current() === $this->rhs->current()
+ && $this->lhs->key() === $this->rhs->key()
+ : $this->lhs->valid() == $this->rhs->valid();
+ }
+
+ /** @return whether both inner iterators are valid and have equal current
+ * and key values or both are non valid.
+ */
+ function areEqual()
+ {
+ return $this->valid()
+ ? $this->lhs->current() == $this->rhs->current()
+ && $this->lhs->key() == $this->rhs->key()
+ : $this->lhs->valid() == $this->rhs->valid();
+ }
+
+ /** Compare two iterators
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param identical whether to use areEqual() or areIdentical()
+ * @return whether both iterators are equal/identical
+ *
+ * @note If one implements RecursiveIterator the other must do as well.
+ * And if both do then a recursive comparison is being used.
+ */
+ static function compareIterators(Iterator $lhs, Iterator $rhs,
+ $identical = false)
+ {
+ if ($lhs instanceof RecursiveIterator)
+ {
+ if ($rhs instanceof RecursiveIterator)
+ {
+ $it = new RecursiveDualIterator($lhs, $rhs,
+ self::CURRENT_0 | self::KEY_0);
+ $it = new RecursiveCompareDualIterator($it);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ $it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0);
+ }
+
+ if ($identical)
+ {
+ foreach($it as $n)
+ {
+ if (!$it->areIdentical())
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ foreach($it as $n)
+ {
+ if (!$it->areEqual())
+ {
+ return false;
+ }
+ }
+ }
+ return $identical ? $it->areIdentical() : $it->areEqual();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/findfile.inc b/ext/spl/examples/findfile.inc
new file mode 100644
index 0000000..02ab792
--- /dev/null
+++ b/ext/spl/examples/findfile.inc
@@ -0,0 +1,65 @@
+<?php
+
+/** @file findfile.inc
+ * @ingroup Examples
+ * @brief class FindFile
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+if (!class_exists("FindFile", false)) require_once("findfile.inc");
+if (!class_exists("AppendIterator", false)) require_once("appenditerator.inc");
+
+/** @ingroup Examples
+ * @brief Base class to find files
+ * @author Marcus Boerger
+ * @version 1.1
+ *
+ */
+class FindFile extends FilterIterator
+{
+ /** @internal filename to find */
+ private $file;
+
+ /** Construct from path and filename
+ *
+ * @param $path the directory to search in
+ * If path contains ';' then this parameter is split and every
+ * part of it is used as separate directory.
+ * @param $file the name of the files to search fro
+ */
+ function __construct($path, $file)
+ {
+ $this->file = $file;
+ $list = split(PATH_SEPARATOR, $path);
+ if (count($list) <= 1) {
+ parent::__construct(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)));
+ } else {
+ $it = new AppendIterator();
+ foreach($list as $path) {
+ $it->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)));
+ }
+ parent::__construct($it);
+ }
+ }
+
+ /** @return whether the current file matches the given filename
+ */
+ function accept()
+ {
+ return !strcmp($this->current(), $this->file);
+ }
+
+ /** @return the filename to search for.
+ * @note This may be overloaded and contain a regular expression for an
+ * extended class that uses regular expressions to search.
+ */
+ function getSearch()
+ {
+ return $this->file;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/findfile.php b/ext/spl/examples/findfile.php
new file mode 100755
index 0000000..60146cb
--- /dev/null
+++ b/ext/spl/examples/findfile.php
@@ -0,0 +1,33 @@
+<?php
+
+/** @file findfile.php
+ * @brief Program Find a specific file by name.
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage: php findfile.php \<path\> \<name\>
+ *
+ * \<path\> Path to search in. You can specify multiple paths by separating
+ * them with ';'.
+ * \<name\> Filename to look for.
+ */
+
+if ($argc < 3) {
+ echo <<<EOF
+Usage: php findfile.php <path> <name>
+
+Find a specific file by name.
+
+<path> Path to search in.
+<name> Filename to look for.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("FindFile", false)) require_once("findfile.inc");
+
+foreach(new FindFile($argv[1], $argv[2]) as $file) echo $file->getPathname()."\n";
+?> \ No newline at end of file
diff --git a/ext/spl/examples/findregex.php b/ext/spl/examples/findregex.php
new file mode 100755
index 0000000..b43ee0c
--- /dev/null
+++ b/ext/spl/examples/findregex.php
@@ -0,0 +1,36 @@
+<?php
+
+/** @file findregex.php
+ * @brief Program Find a specific file by name.
+ * @ingroup Examples
+ * @author Marcus Boerger, Adam Trachtenberg
+ * @date 2004
+ *
+ * Usage: php findregex.php \<path\> \<name\>
+ *
+ * \<path\> Path to search in.
+ * \<name\> Filename to look for.
+ */
+
+if ($argc < 3) {
+ echo <<<EOF
+Usage: php findregex.php <file> <name>
+
+Find a specific file by name.
+
+<path> Path to search in.
+<name> Regex for filenames to look for.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("RegexFindFile", false)) require_once("regexfindfile.inc");
+
+foreach(new RegexFindFile($argv[1], $argv[2]) as $file)
+{
+ echo $file->getPathname()."\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/ini_groups.php b/ext/spl/examples/ini_groups.php
new file mode 100755
index 0000000..5136911
--- /dev/null
+++ b/ext/spl/examples/ini_groups.php
@@ -0,0 +1,41 @@
+<?php
+
+/** @file ini_groups.php
+ * @brief Program List groups within an ini file
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage: php dba_dump.php \<file\> [\<regex\>]
+ *
+ * Show all groups in the ini file specified by \<file\>.
+ * The regular expression \<regex\> is used to filter the result.
+ *
+ * Note: configure with --enable-dba
+ */
+
+if ($argc < 2) {
+ echo <<<EOF
+Usage: php dba_dump.php <file> [<regex>]
+
+Show all groups in the ini file specified by <file>.
+The regular expression <regex> is used to filter the result.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc");
+if (!class_exists("IniGroups", false)) require_once("inigroups.inc");
+
+$it = new IniGroups($argv[1]);
+if ($argc>2) {
+ $it = new KeyFilter($it, $argv[2]);
+}
+
+foreach($it as $group) {
+ echo "$group\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/inigroups.inc b/ext/spl/examples/inigroups.inc
new file mode 100644
index 0000000..62cfa3e
--- /dev/null
+++ b/ext/spl/examples/inigroups.inc
@@ -0,0 +1,54 @@
+<?php
+
+/** @file inigroups.inc
+ * @ingroup Examples
+ * @brief class IniGroups
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc");
+if (!class_exists("DbaReader", false)) require_once("dbareader.inc");
+
+/** @ingroup Examples
+ * @brief Class to iterate all groups within an ini file.
+ * @author Marcus Boerger
+ * @version 1.1
+ *
+ * Using this class you can iterator over all groups of a ini file.
+ *
+ * This class uses a 'is-a' relation to KeyFilter in contrast to a 'has-a'
+ * relation. Doing so both current() and key() methods must be overwritten.
+ * If it would use a 'has-a' relation there would be much more to type...
+ * but for puritists that would allow correctness in so far as then no
+ * key() would be needed.
+ */
+class IniGroups extends KeyFilter
+{
+ /**
+ * Construct an ini file group iterator from a filename.
+ *
+ * @param file Ini file to open.
+ */
+ function __construct($file) {
+ parent::__construct(new DbaReader($file, 'inifile'), '^\[.*\]$');
+ }
+
+ /**
+ * @return The current group.
+ */
+ function current() {
+ return substr(parent::key(),1,-1);
+ }
+
+ /**
+ * @return The current group.
+ */
+ function key() {
+ return substr(parent::key(),1,-1);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/keyfilter.inc b/ext/spl/examples/keyfilter.inc
new file mode 100644
index 0000000..eaf6b77
--- /dev/null
+++ b/ext/spl/examples/keyfilter.inc
@@ -0,0 +1,64 @@
+<?php
+
+/** @file keyfilter.inc
+ * @ingroup Examples
+ * @brief class KeyFilter
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Regular expression filter for string iterators
+ * @author Marcus Boerger
+ * @version 1.1
+ *
+ * Instances of this class act as a filter around iterators whose elements
+ * are strings. In other words you can put an iterator into the constructor
+ * and the instance will only return elements which match the given regular
+ * expression.
+ */
+class KeyFilter extends FilterIterator
+{
+ /** @internal regular exoression used as filter */
+ private $regex;
+
+ /**
+ * Constructs a filter around an iterator whose elemnts are strings.
+ * If the given iterator is of type spl_sequence then its rewind()
+ * method is called.
+ *
+ * @param it Object that implements at least spl_forward
+ * @param regex Regular expression used as a filter.
+ */
+ function __construct(Iterator $it, $regex)
+ {
+ parent::__construct($it);
+ $this->regex = $regex;
+ }
+
+ /** \return whether the current key mathes the regular expression
+ */
+ function accept()
+ {
+ return ereg($this->regex, $this->getInnerIterator()->key());
+ }
+
+ /** @return regular expression used as filter
+ */
+ function getRegex()
+ {
+ return $this->regex;
+ }
+
+ /**
+ * hidden __clone
+ */
+ protected function __clone()
+ {
+ // disallow clone
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/nocvsdir.php b/ext/spl/examples/nocvsdir.php
new file mode 100755
index 0000000..6993268
--- /dev/null
+++ b/ext/spl/examples/nocvsdir.php
@@ -0,0 +1,55 @@
+<?php
+
+/** @file nocvsdir.php
+ * @brief Program Dir without CVS subdirs
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ * @version 1.1
+ *
+ * Usage: php nocvsdir.php \<path\>
+ *
+ * Simply specify the path to tree with parameter \<path\>.
+ */
+
+if ($argc < 2) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <path>
+
+Show the directory and all it's contents without any CVS directory in <path>.
+
+<path> The directory for which to generate the directory.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("RecursiveFilterIterator")) require_once("recursivefilteriterator.inc");
+
+class NoCvsDirectory extends RecursiveFilterIterator
+{
+ function __construct($path)
+ {
+ parent::__construct(new RecursiveDirectoryIterator($path));
+ }
+
+ function accept()
+ {
+ return $this->getInnerIterator()->getFilename() != 'CVS';
+ }
+
+ function getChildren()
+ {
+ return new NoCvsDirectory($this->key());
+ }
+}
+
+$it = new RecursiveIteratorIterator(new NoCvsDirectory($argv[1]));
+
+foreach($it as $pathname => $file)
+{
+ echo $pathname."\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/phar_from_dir.php b/ext/spl/examples/phar_from_dir.php
new file mode 100755
index 0000000..2ee15ca
--- /dev/null
+++ b/ext/spl/examples/phar_from_dir.php
@@ -0,0 +1,50 @@
+<?php
+
+/** @file phar_from_dir.php
+ * @brief Create phar archive from directory
+ * @ingroup examples
+ * @author Marcus Boerger
+ * @date 2003 - 2007
+ * @version 1.0
+ *
+ * Usage: php phar_create_from_dir.php \<archive\> \<directory\> [\<regex\>]
+ *
+ * Create phar archive \<archive\> using entries from \<directory\> that
+ * optionally match \<regex\>.
+ */
+
+if ($argc < 3)
+{
+ echo <<<EOF
+php phar_from_dir.php archive directory [regex]
+
+Packs files in a given directory into a phar archive.
+
+archive name of the archive to create
+directory input directory to pack
+regex optional expression to match files in directory
+
+EOF;
+ exit(1);
+}
+
+$phar = new Phar($argv[1], 0, 'newphar');
+
+$dir = new RecursiveDirectoryIterator($argv[2]);
+$dir = new RecursiveIteratorIterator($dir);
+if ($argc > 3)
+{
+ $dir = new RegexIterator($dir, '/'.$argv[3].'/');
+}
+
+$phar->begin();
+
+foreach($dir as $file)
+{
+ echo "$file\n";
+ copy($file, "phar://newphar/$file");
+}
+
+$phar->commit();
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/recursivecomparedualiterator.inc b/ext/spl/examples/recursivecomparedualiterator.inc
new file mode 100644
index 0000000..75265c1
--- /dev/null
+++ b/ext/spl/examples/recursivecomparedualiterator.inc
@@ -0,0 +1,69 @@
+<?php
+
+/** @file recursivecomparedualiterator.inc
+ * @ingroup Examples
+ * @brief class DualIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Recursive comparison iterator for a RecursiveDualIterator
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class RecursiveCompareDualIterator extends RecursiveIteratorIterator
+{
+ /** Used to keep end of recursion equality. That is en leaving a nesting
+ * level we need to check whether both child iterators are at their end.
+ */
+ protected $equal = false;
+
+ /** Construct from RecursiveDualIterator
+ *
+ * @param $it RecursiveDualIterator
+ * @param $mode should be LEAVES_ONLY
+ * @param $flags should be 0
+ */
+ function __construct(RecursiveDualIterator $it, $mode = self::LEAVES_ONLY, $flags = 0)
+ {
+ parent::__construct($it);
+ }
+
+ /** Rewind iteration andcomparison process. Starting with $equal = true.
+ */
+ function rewind()
+ {
+ $this->equal = true;
+ parent::rewind();
+ }
+
+ /** Calculate $equal
+ * @see $equal
+ */
+ function endChildren()
+ {
+ $this->equal &= !$this->getInnerIterator()->getLHS()->valid()
+ && !$this->getInnerIterator()->getRHS()->valid();
+ }
+
+ /** @return whether both inner iterators are valid and have identical
+ * current and key values or both are non valid.
+ */
+ function areIdentical()
+ {
+ return $this->equal && $this->getInnerIterator()->areIdentical();
+ }
+
+ /** @return whether both inner iterators are valid and have equal current
+ * and key values or both are non valid.
+ */
+ function areEqual()
+ {
+ return $this->equal && $this->getInnerIterator()->areEqual();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/recursivedualiterator.inc b/ext/spl/examples/recursivedualiterator.inc
new file mode 100644
index 0000000..cfa3bcc
--- /dev/null
+++ b/ext/spl/examples/recursivedualiterator.inc
@@ -0,0 +1,72 @@
+<?php
+
+/** @file recursivedualiterator.inc
+ * @ingroup Examples
+ * @brief class RecursiveDualIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Synchronous iteration over two recursive iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class RecursiveDualIterator extends DualIterator implements RecursiveIterator
+{
+ private $ref;
+
+ /** construct iterator from two RecursiveIterator instances
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param flags iteration flags
+ */
+ function __construct(RecursiveIterator $lhs, RecursiveIterator $rhs,
+ $flags = 0x33 /*DualIterator::DEFAULT_FLAGS*/)
+ {
+ parent::__construct($lhs, $rhs, $flags);
+ }
+
+ /** @return whether both LHS and RHS have children
+ */
+ function hasChildren()
+ {
+ return $this->getLHS()->hasChildren() && $this->getRHS()->hasChildren();
+ }
+
+ /** @return new RecursiveDualIterator (late binding) for the two inner
+ * iterators current children.
+ */
+ function getChildren()
+ {
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance(
+ $this->getLHS()->getChildren(), $this->getRHS()->getChildren(), $this->getFlags());
+ }
+
+ /** @return whether both inner iterators are valid, have same hasChildren()
+ * state and identical current and key values or both are non valid.
+ */
+ function areIdentical()
+ {
+ return $this->getLHS()->hasChildren() === $this->getRHS()->hasChildren()
+ && parent::areIdentical();
+ }
+
+ /** @return whether both inner iterators are valid, have same hasChildren()
+ * state and equal current and key values or both are invalid.
+ */
+ function areEqual()
+ {
+ return $this->getLHS()->hasChildren() === $this->getRHS()->hasChildren()
+ && parent::areEqual();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/regexfindfile.inc b/ext/spl/examples/regexfindfile.inc
new file mode 100644
index 0000000..d5dd722
--- /dev/null
+++ b/ext/spl/examples/regexfindfile.inc
@@ -0,0 +1,40 @@
+<?php
+
+/** @file regexfindfile.inc
+ * @ingroup Examples
+ * @brief class RegexFindFile
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Find files by regular expression
+ * @author Marcus Boerger
+ * @version 1.1
+ *
+ */
+class RegexFindFile extends FindFile
+{
+ /** Construct from path and regular expression
+ *
+ * @param $path the directory to search in
+ * If path contains ';' then this parameter is split and every
+ * part of it is used as separate directory.
+ * @param $regex perl style regular expression to find files with
+ */
+ function __construct($path, $regex)
+ {
+ parent::__construct($path, $regex);
+ }
+
+ /** @return whether the current filename matches the regular expression.
+ */
+ function accept()
+ {
+ return preg_match($this->getSearch(), $this->current());
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/searchiterator.inc b/ext/spl/examples/searchiterator.inc
new file mode 100644
index 0000000..944a4ac
--- /dev/null
+++ b/ext/spl/examples/searchiterator.inc
@@ -0,0 +1,58 @@
+<?php
+
+/** @file searchiterator.inc
+ * @ingroup Examples
+ * @brief abstract class SearchIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Iterator to search for a specific element
+ * @author Marcus Boerger
+ * @version 1.0
+ *
+ * This extended FilterIterator stops after finding the first acceptable
+ * value.
+ */
+abstract class SearchIterator extends FilterIterator
+{
+ /** @internal whether an entry was found already */
+ private $done = false;
+
+ /** Rewind and reset so that it once again searches.
+ * @return void
+ */
+ function rewind()
+ {
+ parent::rewind();
+ $this->done = false;
+ }
+
+ /** @return whether the current element is valid
+ * which can only happen once per iteration.
+ */
+ function valid()
+ {
+ return !$this->done && parent::valid();
+ }
+
+ /** Do not move forward but instead mark as finished.
+ * @return void
+ */
+ function next()
+ {
+ $this->done = true;
+ }
+
+ /** Aggregates the inner iterator
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->getInnerIterator(), $func), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/tests/dualiterator_001.phpt b/ext/spl/examples/tests/dualiterator_001.phpt
new file mode 100644
index 0000000..53c1153
--- /dev/null
+++ b/ext/spl/examples/tests/dualiterator_001.phpt
@@ -0,0 +1,48 @@
+--TEST--
+SPL: DualIterator
+--SKIPIF--
+<?php if (!extension_loaded("spl") || !extension_loaded("reflection")) print "skip"; ?>
+--FILE--
+<?php
+
+function spl_examples_autoload($classname)
+{
+ include(dirname(__FILE__) . '/../' . strtolower($classname) . '.inc');
+}
+
+spl_autoload_register('spl_examples_autoload');
+
+function test($a, $b, $identical = false)
+{
+ var_dump(DualIterator::compareIterators(
+ new RecursiveArrayIterator($a),
+ new RecursiveArrayIterator($b),
+ $identical));
+}
+
+test(array(1,2,3), array(1,2,3));
+test(array(1,2,3), array(1,2));
+test(array(1,array(21,22),3), array(1,array(21,22),3));
+test(array(1,array(21,22),3), array(1,array(21,22,23),3));
+test(array(1,array(21,22),3), array(1,array(21,22,3)));
+test(array(1,array(21,22),3), array(1,array(21),array(22),3));
+test(array(1,2,3), array(1,"2",3), false);
+test(array(1,2,3), array(1,"2",3), true);
+test(array(1,array(21,22),3), array(1,array(21,"22"),3), false);
+test(array(1,array(21,22),3), array(1,array(21,"22"),3), true);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+===DONE===
diff --git a/ext/spl/examples/tests/examples.inc b/ext/spl/examples/tests/examples.inc
new file mode 100644
index 0000000..feeba7d
--- /dev/null
+++ b/ext/spl/examples/tests/examples.inc
@@ -0,0 +1,23 @@
+<?php
+
+class IncludeFiles extends ArrayIterator
+{
+ function __construct($path, $classes)
+ {
+ parent::__construct();
+ foreach($classes as $c)
+ {
+ $this->append($path . '/' . strtolower($c) . '.inc');
+ }
+ }
+}
+
+$classes = array(
+);
+
+foreach (new IncludeFiles(dirname(__FILE__). '/..', $classes) as $file)
+{
+ require_once($file);
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/examples/tree.php b/ext/spl/examples/tree.php
new file mode 100755
index 0000000..9c2cc55
--- /dev/null
+++ b/ext/spl/examples/tree.php
@@ -0,0 +1,40 @@
+<?php
+
+/** @file tree.php
+ * @brief Program Tree view example
+ * @ingroup Examples
+ * @author Marcus Boerger
+ * @date 2003 - 2005
+ *
+ * Usage: php tree.php \<path\>
+ *
+ * Simply specify the path to tree with parameter \<path\>.
+ */
+
+// The following line only operates on classes which are converted to c already.
+// But does not generate a graphical output.
+//foreach(new RecursiveIteratorIterator(new ParentIterator(new RecursiveDirectoryIterator($argv[1])), 1) as $file) {
+
+if ($argc < 2) {
+ echo <<<EOF
+Usage: php ${_SERVER['PHP_SELF']} <path>
+
+Displays a graphical tree for the given <path>.
+
+<path> The directory for which to generate the tree graph.
+
+
+EOF;
+ exit(1);
+}
+
+if (!class_exists("DirectoryTreeIterator", false)) require_once("directorytreeiterator.inc");
+if (!class_exists("DirectoryGraphIterator", false)) require_once("directorygraphiterator.inc");
+
+echo $argv[1]."\n";
+foreach(new DirectoryGraphIterator($argv[1]) as $file)
+{
+ echo $file . "\n";
+}
+
+?>
diff --git a/ext/spl/internal/appenditerator.inc b/ext/spl/internal/appenditerator.inc
new file mode 100644
index 0000000..28e32b1
--- /dev/null
+++ b/ext/spl/internal/appenditerator.inc
@@ -0,0 +1,122 @@
+<?php
+
+/** @file appenditerator.inc
+ * @ingroup SPL
+ * @brief class AppendIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Iterator that iterates over several iterators one after the other
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ */
+class AppendIterator implements OuterIterator
+{
+ /** @internal array of inner iterators */
+ private $iterators;
+
+ /** Construct an empty AppendIterator
+ */
+ function __construct()
+ {
+ $this->iterators = new ArrayIterator();
+ }
+
+ /** Append an Iterator
+ * @param $it Iterator to append
+ *
+ * If the current state is invalid but the appended iterator is valid
+ * the AppendIterator itself becomes valid. However there will be no
+ * call to $it->rewind(). Also if the current state is invalid the inner
+ * ArrayIterator will be rewound und forwarded to the appended element.
+ */
+ function append(Iterator $it)
+ {
+ $this->iterators->append($it);
+ }
+
+ /** @return the current inner Iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->iterators->current();
+ }
+
+ /** Rewind to the first element of the first inner Iterator.
+ * @return void
+ */
+ function rewind()
+ {
+ $this->iterators->rewind();
+ if ($this->iterators->valid())
+ {
+ $this->getInnerIterator()->rewind();
+ }
+ }
+
+ /** @return whether the current element is valid
+ */
+ function valid()
+ {
+ return $this->iterators->valid() && $this->getInnerIterator()->valid();
+ }
+
+ /** @return the current value if it is valid or \c NULL
+ */
+ function current()
+ {
+ /* Using $this->valid() would be exactly the same; it would omit
+ * the access to a non valid element in the inner iterator. Since
+ * the user didn't respect the valid() return value false this
+ * must be intended hence we go on. */
+ return $this->iterators->valid() ? $this->getInnerIterator()->current() : NULL;
+ }
+
+ /** @return the current key if it is valid or \c NULL
+ */
+ function key()
+ {
+ return $this->iterators->valid() ? $this->getInnerIterator()->key() : NULL;
+ }
+
+ /** Move to the next element. If this means to another Iterator that
+ * rewind that Iterator.
+ * @return void
+ */
+ function next()
+ {
+ if (!$this->iterators->valid())
+ {
+ return; /* done all */
+ }
+ $this->getInnerIterator()->next();
+ if ($this->getInnerIterator()->valid())
+ {
+ return; /* found valid element in current inner iterator */
+ }
+ $this->iterators->next();
+ while ($this->iterators->valid())
+ {
+ $this->getInnerIterator()->rewind();
+ if ($this->getInnerIterator()->valid())
+ {
+ return; /* found element as first elemet in another iterator */
+ }
+ $this->iterators->next();
+ }
+ }
+
+ /** Aggregates the inner iterator
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->getInnerIterator(), $func), $params);
+ }
+}
+
+?>
diff --git a/ext/spl/internal/cachingiterator.inc b/ext/spl/internal/cachingiterator.inc
new file mode 100644
index 0000000..33258ab
--- /dev/null
+++ b/ext/spl/internal/cachingiterator.inc
@@ -0,0 +1,157 @@
+<?php
+
+/** @file cachingiterator.inc
+ * @ingroup SPL
+ * @brief class CachingIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Cached iteration over another Iterator
+ * @author Marcus Boerger
+ * @version 1.2
+ * @since PHP 5.0
+ *
+ * This iterator wrapper does a one ahead iteration. This way it knows whether
+ * the inner iterator has one more element.
+ *
+ * @note If you want to convert the elements into strings and the inner
+ * Iterator is an internal Iterator then you need to provide the
+ * flag CALL_TOSTRING to do the conversion when the actual element
+ * is being fetched. Otherwise the conversion would happen with the
+ * already changed iterator. If you do not need this then it you should
+ * omit this flag because it costs unneccessary work and time.
+ */
+class CachingIterator implements OuterIterator
+{
+ const CALL_TOSTRING = 0x00000001;
+ const CATCH_GET_CHILD = 0x00000002;
+ const TOSTRING_USE_KEY = 0x00000010;
+ const TOSTRING_USE_CURRENT = 0x00000020;
+
+ private $it;
+ private $current;
+ private $key;
+ private $valid;
+ private $strValue;
+
+ /** Construct from another iterator
+ *
+ * @param it Iterator to cache
+ * @param flags Bitmask:
+ * - CALL_TOSTRING (whether to call __toString() for every element)
+ */
+ function __construct(Iterator $it, $flags = self::CALL_TOSTRING)
+ {
+ if ((($flags & self::CALL_TOSTRING) && ($flags & (self::TOSTRING_USE_KEY|self::TOSTRING_USE_CURRENT)))
+ || ((flags & (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)) == (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)))
+ {
+ throw new InvalidArgumentException('Flags must contain only one of CIT_CALL_TOSTRING, CIT_TOSTRING_USE_KEY, CIT_TOSTRING_USE_CURRENT');
+ }
+ $this->it = $it;
+ $this->flags = $flags & (0x0000FFFF);
+ $this->next();
+ }
+
+ /** Rewind the Iterator
+ */
+ function rewind()
+ {
+ $this->it->rewind();
+ $this->next();
+ }
+
+ /** Forward to the next element
+ */
+ function next()
+ {
+ if ($this->valid = $this->it->valid()) {
+ $this->current = $this->it->current();
+ $this->key = $this->it->key();
+ if ($this->flags & self::CALL_TOSTRING) {
+ if (is_object($this->current)) {
+ $this->strValue = $this->current->__toString();
+ } else {
+ $this->strValue = (string)$this->current;
+ }
+ }
+ } else {
+ $this->current = NULL;
+ $this->key = NULL;
+ $this->strValue = NULL;
+ }
+ $this->it->next();
+ }
+
+ /** @return whether the iterator is valid
+ */
+ function valid()
+ {
+ return $this->valid;
+ }
+
+ /** @return whether there is one more element
+ */
+ function hasNext()
+ {
+ return $this->it->valid();
+ }
+
+ /** @return the current element
+ */
+ function current()
+ {
+ return $this->current;
+ }
+
+ /** @return the current key
+ */
+ function key()
+ {
+ return $this->key;
+ }
+
+ /** Aggregate the inner iterator
+ *
+ * @param func Name of method to invoke
+ * @param params Array of parameters to pass to method
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->it, $func), $params);
+ }
+
+ /** @return the string represenatation that was generated for the current
+ * element
+ * @throw exception when CALL_TOSTRING was not specified in constructor
+ */
+ function __toString()
+ {
+ if ($this->flags & self::TOSTRING_USE_KEY)
+ {
+ return $this->key;
+ }
+ else if ($this->flags & self::TOSTRING_USE_CURRENT)
+ {
+ return $this->current;
+ }
+ if (!$this->flags & self::CALL_TOSTRING)
+ {
+ throw new exception('CachingIterator does not fetch string value (see CachingIterator::__construct)');
+ }
+ return $this->strValue;
+ }
+
+ /**
+ * @return The inner iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->it;
+ }
+}
+
+?>
diff --git a/ext/spl/internal/emptyiterator.inc b/ext/spl/internal/emptyiterator.inc
new file mode 100644
index 0000000..ac80e79
--- /dev/null
+++ b/ext/spl/internal/emptyiterator.inc
@@ -0,0 +1,62 @@
+<?php
+
+/** @file emptyiterator.inc
+ * @ingroup SPL
+ * @brief class EmptyIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief An empty Iterator
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ */
+class EmptyIterator implements Iterator
+{
+ /** No operation.
+ * @return void
+ */
+ function rewind()
+ {
+ // nothing to do
+ }
+
+ /** @return \c false
+ */
+ function valid()
+ {
+ return false;
+ }
+
+ /** This function must not be called. It throws an exception upon access.
+ * @throw Exception
+ * @return void
+ */
+ function current()
+ {
+ throw new Exception('Accessing the value of an EmptyIterator');
+ }
+
+ /** This function must not be called. It throws an exception upon access.
+ * @throw Exception
+ * @return void
+ */
+ function key()
+ {
+ throw new Exception('Accessing the key of an EmptyIterator');
+ }
+
+ /** No operation.
+ * @return void
+ */
+ function next()
+ {
+ // nothing to do
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/filteriterator.inc b/ext/spl/internal/filteriterator.inc
new file mode 100644
index 0000000..3330cc9
--- /dev/null
+++ b/ext/spl/internal/filteriterator.inc
@@ -0,0 +1,127 @@
+<?php
+
+/** @file filteriterator.inc
+ * @ingroup SPL
+ * @brief class FilterIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Abstract filter for iterators
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.0
+ *
+ * Instances of this class act as a filter around iterators. In other words
+ * you can put an iterator into the constructor and the instance will only
+ * return selected (accepted) elements.
+ *
+ * The only thing that needs to be done to make this work is implementing
+ * method accept(). Typically this invloves reading the current element or
+ * key of the inner Iterator and checking whether it is acceptable.
+ */
+abstract class FilterIterator implements OuterIterator
+{
+ private $it;
+
+ /**
+ * Constructs a filter around another iterator.
+ *
+ * @param it Iterator to filter
+ */
+ function __construct(Iterator $it) {
+ $this->it = $it;
+ }
+
+ /**
+ * Rewind the inner iterator.
+ */
+ function rewind() {
+ $this->it->rewind();
+ $this->fetch();
+ }
+
+ /**
+ * Accept function to decide whether an element of the inner iterator
+ * should be accessible through the Filteriterator.
+ *
+ * @return whether or not to expose the current element of the inner
+ * iterator.
+ */
+ abstract function accept();
+
+ /**
+ * Fetch next element and store it.
+ *
+ * @return void
+ */
+ protected function fetch() {
+ while ($this->it->valid()) {
+ if ($this->accept()) {
+ return;
+ }
+ $this->it->next();
+ };
+ }
+
+ /**
+ * Move to next element
+ *
+ * @return void
+ */
+ function next() {
+ $this->it->next();
+ $this->fetch();
+ }
+
+ /**
+ * @return Whether more elements are available
+ */
+ function valid() {
+ return $this->it->valid();
+ }
+
+ /**
+ * @return The current key
+ */
+ function key() {
+ return $this->it->key();
+ }
+
+ /**
+ * @return The current value
+ */
+ function current() {
+ return $this->it->current();
+ }
+
+ /**
+ * hidden __clone
+ */
+ protected function __clone() {
+ // disallow clone
+ }
+
+ /**
+ * @return The inner iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->it;
+ }
+
+ /** Aggregate the inner iterator
+ *
+ * @param func Name of method to invoke
+ * @param params Array of parameters to pass to method
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->it, $func), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/infiniteiterator.inc b/ext/spl/internal/infiniteiterator.inc
new file mode 100644
index 0000000..04d7827
--- /dev/null
+++ b/ext/spl/internal/infiniteiterator.inc
@@ -0,0 +1,48 @@
+<?php
+
+/** @file infiniteiterator.inc
+ * @ingroup SPL
+ * @brief class InfiniteIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief An infinite Iterator
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.1
+ *
+ * This Iterator takes another Iterator and infinitvely iterates it by
+ * rewinding it when its end is reached.
+ *
+ * \note Even an InfiniteIterator stops if its inner Iterator is empty.
+ *
+ \verbatim
+ $it = new ArrayIterator(array(1,2,3));
+ $infinite = new InfiniteIterator($it);
+ $limit = new LimitIterator($infinite, 0, 5);
+ foreach($limit as $val=>$key)
+ {
+ echo "$val=>$key\n";
+ }
+ \endverbatim
+ */
+class InfiniteIterator extends IteratorIterator
+{
+ /** Move the inner Iterator forward to its next element or rewind it.
+ * @return void
+ */
+ function next()
+ {
+ $this->getInnerIterator()->next();
+ if (!$this->getInnerIterator()->valid())
+ {
+ $this->getInnerIterator()->rewind();
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/iteratoriterator.inc b/ext/spl/internal/iteratoriterator.inc
new file mode 100644
index 0000000..37676e0
--- /dev/null
+++ b/ext/spl/internal/iteratoriterator.inc
@@ -0,0 +1,121 @@
+<?php
+
+/** @file iteratoriterator.inc
+ * @ingroup SPL
+ * @brief class IteratorIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Basic Iterator wrapper
+ * @since PHP 5.1
+ *
+ * This iterator wrapper allows to convert anything that is traversable into
+ * an Iterator. It is very important to understand that most classes that do
+ * not implement Iterator have their reasone to. Most likely they do not allow
+ * the full Iterator feature set. If so you need to provide techniques to
+ * prevent missuse. If you do not you must expect exceptions or fatal erros.
+ *
+ * It is also possible to derive the class and implement IteratorAggregate by
+ * downcasting the instances returned in getIterator. See the following
+ * example (assuming BaseClass implements Traversable):
+ \code
+ class SomeClass extends BaseClass implements IteratorAggregate
+ {
+ function getIterator()
+ {
+ return new IteratorIterator($this, 'BaseClass');
+ }
+ }
+ \endcode
+ *
+ * As you can see in the example this approach requires that the class to
+ * downcast to is actually a base class of the specified iterator to wrap.
+ * Omitting the downcast in the above example would result in an endless loop
+ * since IteratorIterator::__construct() would call SomeClass::getIterator().
+ */
+class IteratorIterator implements OuterIterator
+{
+ /** Construct an IteratorIterator from an Iterator or an IteratorAggregate.
+ *
+ * @param iterator inner iterator
+ * @param classname optional class the iterator has to be downcasted to
+ */
+ function __construct(Traversable $iterator, $classname = null)
+ {
+ if ($iterator instanceof IteratorAggregate)
+ {
+ $iterator = $iterator->getIterator();
+ }
+ if ($iterator instanceof Iterator)
+ {
+ $this->iterator = $iterator;
+ }
+ else
+ {
+ throw new Exception("Classes that only implement Traversable can be wrapped only after converting class IteratorIterator into c code");
+ }
+ }
+
+ /** \return the inner iterator as passed to the constructor
+ */
+ function getInnerIterator()
+ {
+ return $this->iterator;
+ }
+
+ /** \return whether the iterator is valid
+ */
+ function valid()
+ {
+ return $this->iterator->valid();
+ }
+
+ /** \return current key
+ */
+ function key()
+ {
+ return $this->iterator->key();
+ }
+
+ /** \return current value
+ */
+ function current()
+ {
+ return $this->iterator->current();
+ }
+
+ /** forward to next element
+ */
+ function next()
+ {
+ return $this->iterator->next();
+ }
+
+ /** rewind to the first element
+ */
+ function rewind()
+ {
+ return $this->iterator->rewind();
+ }
+
+ /** Aggregate the inner iterator
+ *
+ * @param func Name of method to invoke
+ * @param params Array of parameters to pass to method
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->iterator, $func), $params);
+ }
+
+ /** The inner iterator must be private because when this class will be
+ * converted to c code it won't no longer be available.
+ */
+ private $iterator;
+}
+
+?>
diff --git a/ext/spl/internal/limititerator.inc b/ext/spl/internal/limititerator.inc
new file mode 100644
index 0000000..c5bddea
--- /dev/null
+++ b/ext/spl/internal/limititerator.inc
@@ -0,0 +1,134 @@
+<?php
+
+/** @file limititerator.inc
+ * @ingroup SPL
+ * @brief class LimitIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Limited Iteration over another Iterator
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.0
+ *
+ * A class that starts iteration at a certain offset and only iterates over
+ * a specified amount of elements.
+ *
+ * This class uses SeekableIterator::seek() if available and rewind() plus
+ * a skip loop otehrwise.
+ */
+class LimitIterator implements OuterIterator
+{
+ private $it;
+ private $offset;
+ private $count;
+ private $pos;
+
+ /** Construct
+ *
+ * @param it Iterator to limit
+ * @param offset Offset to first element
+ * @param count Maximum number of elements to show or -1 for all
+ */
+ function __construct(Iterator $it, $offset = 0, $count = -1)
+ {
+ if ($offset < 0) {
+ throw new exception('Parameter offset must be > 0');
+ }
+ if ($count < 0 && $count != -1) {
+ throw new exception('Parameter count must either be -1 or a value greater than or equal to 0');
+ }
+ $this->it = $it;
+ $this->offset = $offset;
+ $this->count = $count;
+ $this->pos = 0;
+ }
+
+ /** Seek to specified position
+ * @param position offset to seek to (relative to beginning not offset
+ * specified in constructor).
+ * @throw exception when position is invalid
+ */
+ function seek($position) {
+ if ($position < $this->offset) {
+ throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset);
+ }
+ if ($position > $this->offset + $this->count && $this->count != -1) {
+ throw new exception('Cannot seek to '.$position.' which is behind offset '.$this->offset.' plus count '.$this->count);
+ }
+ if ($this->it instanceof SeekableIterator) {
+ $this->it->seek($position);
+ $this->pos = $position;
+ } else {
+ while($this->pos < $position && $this->it->valid()) {
+ $this->next();
+ }
+ }
+ }
+
+ /** Rewind to offset specified in constructor
+ */
+ function rewind()
+ {
+ $this->it->rewind();
+ $this->pos = 0;
+ $this->seek($this->offset);
+ }
+
+ /** @return whether iterator is valid
+ */
+ function valid() {
+ return ($this->count == -1 || $this->pos < $this->offset + $this->count)
+ && $this->it->valid();
+ }
+
+ /** @return current key
+ */
+ function key() {
+ return $this->it->key();
+ }
+
+ /** @return current element
+ */
+ function current() {
+ return $this->it->current();
+ }
+
+ /** Forward to nect element
+ */
+ function next() {
+ $this->it->next();
+ $this->pos++;
+ }
+
+ /** @return current position relative to zero (not to offset specified in
+ * constructor).
+ */
+ function getPosition() {
+ return $this->pos;
+ }
+
+ /**
+ * @return The inner iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->it;
+ }
+
+ /** Aggregate the inner iterator
+ *
+ * @param func Name of method to invoke
+ * @param params Array of parameters to pass to method
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->it, $func), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/multipleiterator.inc b/ext/spl/internal/multipleiterator.inc
new file mode 100644
index 0000000..2ed71d5
--- /dev/null
+++ b/ext/spl/internal/multipleiterator.inc
@@ -0,0 +1,223 @@
+<?php
+/** @file multipleiterator.inc
+ * @ingroup SPL
+ * @brief class MultipleIterator
+ * @author Johannes Schlueter
+ * @author Marcus Boerger
+ * @date 2008 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Iterator that iterates over several iterators one after the other
+ * @author Johannes Schlueter
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.3
+ */
+class MultipleIterator implements Iterator
+{
+ /** Inner Iterators */
+ private $iterators;
+
+ /** Flags: const MIT_* */
+ private $flags;
+
+ /** do not require all sub iterators to be valid in iteration */
+ const MIT_NEED_ANY = 0;
+
+ /** require all sub iterators to be valid in iteration */
+ const MIT_NEED_ALL = 1;
+
+ /** keys are created from sub iterators position */
+ const MIT_KEYS_NUMERIC = 0;
+
+ /** keys are created from sub iterators associated infromation */
+ const MIT_KEYS_ASSOC = 2;
+
+ /** Construct a new empty MultipleIterator
+ * @param flags MIT_* flags
+ */
+ public function __construct($flags = self::MIT_NEED_ALL|self::MIT_KEYS_NUMERIC)
+ {
+ $this->iterators = new SplObjectStorage();
+ $this->flags = $flags;
+ }
+
+ /** @return current flags MIT_* */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** @param $flags new flags. */
+ public function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /** @param $iter new Iterator to attach.
+ * @param $inf associative info forIteraotr, must be NULL, integer or string
+ *
+ * @throws IllegalValueException if a inf is none of NULL, integer or string
+ * @throws IllegalValueException if a inf is already an associated info
+ */
+ public function attachIterator(Iterator $iter, $inf = NULL)
+ {
+
+ if (!is_null($inf))
+ {
+ if (!is_int($inf) && !is_string($inf))
+ {
+ throw new IllegalValueException('Inf must be NULL, integer or string');
+ }
+ foreach($this->iterators as $iter)
+ {
+ if ($inf == $this->iterators->getInfo())
+ {
+ throw new IllegalValueException('Key duplication error');
+ }
+ }
+ }
+ $this->iterators->attach($iter, $inf);
+ }
+
+ /** @param $iter attached Iterator that should be detached. */
+ public function detachIterator(Iterator $iter)
+ {
+ $this->iterators->detach($iter);
+ }
+
+ /** @param $iter Iterator to check
+ * @return whether $iter is attached or not
+ */
+ public function containsIterator(Iterator $iter)
+ {
+ return $this->iterator->contains($iter);
+ }
+
+ /** @return number of attached Iterator instances. */
+ public function countIterators()
+ {
+ return $this->iterators->count();
+ }
+
+ /** Rewind all attached Iterator instances. */
+ public function rewind()
+ {
+ foreach($this->iterators as $iter)
+ {
+ $iter->rewind();
+ }
+ }
+
+ /**
+ * @return whether all or one sub iterator is valid depending on flags.
+ * In mode MIT_NEED_ALL we expect all sub iterators to be valid and
+ * return flase on the first non valid one. If that flag is not set we
+ * return true on the first valid sub iterator found. If no Iterator
+ * is attached, we always return false.
+ */
+ public function valid()
+ {
+ if (!sizeof($this->iterators)) {
+ return false;
+ }
+ // The following code is an optimized version that executes as few
+ // valid() calls as necessary and that only checks the flags once.
+ $expect = $this->flags & self::MIT_NEED_ALL ? true : false;
+ foreach($this->iterators as $iter)
+ {
+ if ($expect != $iter->valid())
+ {
+ return !$expect;
+ }
+ }
+ return $expect;
+ }
+
+ /** Move all attached Iterator instances forward. That is invoke
+ * their next() method regardless of their state.
+ */
+ public function next()
+ {
+ foreach($this->iterators as $iter)
+ {
+ $iter->next();
+ }
+ }
+
+ /** @return false if no sub Iterator is attached and an array of
+ * all registered Iterator instances current() result.
+ * @throws RuntimeException if mode MIT_NEED_ALL is set and at least one
+ * attached Iterator is not valid().
+ * @throws IllegalValueException if a key is NULL and MIT_KEYS_ASSOC is set.
+ */
+ public function current()
+ {
+ if (!sizeof($this->iterators))
+ {
+ return false;
+ }
+ $retval = array();
+ foreach($this->iterators as $iter)
+ {
+ if ($it->valid())
+ {
+ if ($this->flags & self::MIT_KEYS_ASSOC)
+ {
+ $key = $this->iterators->getInfo();
+ if (is_null($key))
+ {
+ throw new IllegalValueException('Sub-Iterator is associated with NULL');
+ }
+ $retval[$key] = $iter->current();
+ }
+ else
+ {
+ $retval[] = $iter->current();
+ }
+ }
+ else if ($this->flags & self::MIT_NEED_ALL)
+ {
+ throw new RuntimeException('Called current() with non valid sub iterator');
+ }
+ else
+ {
+ $retval[] = NULL;
+ }
+ }
+ return $retval;
+ }
+
+ /** @return false if no sub Iterator is attached and an array of
+ * all registered Iterator instances key() result.
+ * @throws LogicException if mode MIT_NEED_ALL is set and at least one
+ * attached Iterator is not valid().
+ */
+ public function key()
+ {
+ if (!sizeof($this->iterators))
+ {
+ return false;
+ }
+ $retval = array();
+ foreach($this->iterators as $iter)
+ {
+ if ($it->valid())
+ {
+ $retval[] = $iter->key();
+ }
+ else if ($this->flags & self::MIT_NEED_ALL)
+ {
+ throw new LogicException('Called key() with non valid sub iterator');
+ }
+ else
+ {
+ $retval[] = NULL;
+ }
+ }
+ return $retval;
+ }
+}
diff --git a/ext/spl/internal/norewinditerator.inc b/ext/spl/internal/norewinditerator.inc
new file mode 100644
index 0000000..8747a61
--- /dev/null
+++ b/ext/spl/internal/norewinditerator.inc
@@ -0,0 +1,28 @@
+<?php
+
+/** @file norewinditerator.inc
+ * @ingroup SPL
+ * @brief class NoRewindIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief An Iterator wrapper that doesn't call rewind
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.1
+ */
+class NoRewindIterator extends IteratorIterator
+{
+ /** Simply prevent execution of inner iterators rewind().
+ */
+ function rewind()
+ {
+ // nothing to do
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/outeriterator.inc b/ext/spl/internal/outeriterator.inc
new file mode 100644
index 0000000..f26d29d
--- /dev/null
+++ b/ext/spl/internal/outeriterator.inc
@@ -0,0 +1,25 @@
+<?php
+
+/** @file outeriterator.inc
+ * @ingroup SPL
+ * @brief class OuterIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Interface to access the current inner iteraor of iterator wrappers
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ */
+interface OuterIterator extends Iterator
+{
+ /** @return inner iterator
+ */
+ function getInnerIterator();
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/parentiterator.inc b/ext/spl/internal/parentiterator.inc
new file mode 100644
index 0000000..cc377fc
--- /dev/null
+++ b/ext/spl/internal/parentiterator.inc
@@ -0,0 +1,32 @@
+<?php
+
+/** @file parentiterator.inc
+ * @ingroup SPL
+ * @brief class FilterIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Iterator to filter parents
+ * @author Marcus Boerger
+ * @version 1.2
+ * @since PHP 5.1
+ *
+ * This extended FilterIterator allows a recursive iteration using
+ * RecursiveIteratorIterator that only shows those elements which have
+ * children.
+ */
+class ParentIterator extends RecursiveFilterIterator
+{
+ /** @return whetehr the current element has children
+ */
+ function accept()
+ {
+ return $this->it->hasChildren();
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursivearrayiterator.inc b/ext/spl/internal/recursivearrayiterator.inc
new file mode 100644
index 0000000..a9450e1
--- /dev/null
+++ b/ext/spl/internal/recursivearrayiterator.inc
@@ -0,0 +1,59 @@
+<?php
+
+/** @file recursivearrayiterator.inc
+ * @ingroup Examples
+ * @brief class RecursiveArrayIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief A recursive array iterator
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * Passes the RecursiveIterator interface to the inner Iterator and provides
+ * the same functionality as FilterIterator. This allows you to skip parents
+ * and all their childs before loading them all. You need to care about
+ * function getChildren() because it may not always suit your needs. The
+ * builtin behavior uses reflection to return a new instance of the exact same
+ * class it is called from. That is you extend RecursiveFilterIterator and
+ * getChildren() will create instance of that class. The problem is that doing
+ * this does not transport any state or control information of your accept()
+ * implementation to the new instance. To overcome this problem you might
+ * need to overwrite getChildren(), call this implementation and pass the
+ * control vaules manually.
+ */
+class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
+{
+ /** @return whether the current element has children
+ */
+ function hasChildren()
+ {
+ return is_array($this->current());
+ }
+
+ /** @return an iterator for the current elements children
+ *
+ * @note the returned iterator will be of the same class as $this
+ */
+ function getChildren()
+ {
+ if ($this->current() instanceof self)
+ {
+ return $this->current();
+ }
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance($this->current());
+ }
+
+ private $ref;
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursivecachingiterator.inc b/ext/spl/internal/recursivecachingiterator.inc
new file mode 100644
index 0000000..0676d43
--- /dev/null
+++ b/ext/spl/internal/recursivecachingiterator.inc
@@ -0,0 +1,99 @@
+<?php
+
+/** @file recursivecachingiterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveCachingIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Cached recursive iteration over another Iterator
+ * @author Marcus Boerger
+ * @version 1.2
+ * @since PHP 5.1
+ *
+ * @see CachingIterator
+ */
+class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator
+{
+ private $hasChildren;
+ private $getChildren;
+
+ /** Construct from another iterator
+ *
+ * @param it Iterator to cache
+ * @param flags Bitmask:
+ * - CALL_TOSTRING (whether to call __toString() for every element)
+ * - CATCH_GET_CHILD (whether to catch exceptions when trying to get childs)
+ */
+ function __construct(RecursiveIterator $it, $flags = self::CALL_TOSTRING)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ /** Rewind Iterator
+ */
+ function rewind();
+ {
+ $this->hasChildren = false;
+ $this->getChildren = NULL;
+ parent::rewind();
+ }
+
+ /** Forward to next element if necessary then an Iterator for the Children
+ * will be created.
+ */
+ function next()
+ {
+ if ($this->hasChildren = $this->it->hasChildren())
+ {
+ try
+ {
+ $child = $this->it->getChildren();
+ if (!$this->ref)
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ $this->getChildren = $ref->newInstance($child, $this->flags);
+ }
+ catch(Exception $e)
+ {
+ if (!$this->flags & self::CATCH_GET_CHILD)
+ {
+ throw $e;
+ }
+ $this->hasChildren = false;
+ $this->getChildren = NULL;
+ }
+ } else
+ {
+ $this->getChildren = NULL;
+ }
+ parent::next();
+ }
+
+ private $ref;
+
+ /** @return whether the current element has children
+ * @note The check whether the Iterator for the children can be created was
+ * already executed. Hence when flag CATCH_GET_CHILD was given in
+ * constructor this fucntion returns false so that getChildren does
+ * not try to access those children.
+ */
+ function hasChildren()
+ {
+ return $this->hasChildren;
+ }
+
+ /** @return An Iterator for the children
+ */
+ function getChildren()
+ {
+ return $this->getChildren;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursivefilteriterator.inc b/ext/spl/internal/recursivefilteriterator.inc
new file mode 100644
index 0000000..b089919
--- /dev/null
+++ b/ext/spl/internal/recursivefilteriterator.inc
@@ -0,0 +1,62 @@
+<?php
+
+/** @file recursivefilteriterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveFilterIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Iterator to filter recursive iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * Passes the RecursiveIterator interface to the inner Iterator and provides
+ * the same functionality as FilterIterator. This allows you to skip parents
+ * and all their childs before loading them all. You need to care about
+ * function getChildren() because it may not always suit your needs. The
+ * builtin behavior uses reflection to return a new instance of the exact same
+ * class it is called from. That is you extend RecursiveFilterIterator and
+ * getChildren() will create instance of that class. The problem is that doing
+ * this does not transport any state or control information of your accept()
+ * implementation to the new instance. To overcome this problem you might
+ * need to overwrite getChildren(), call this implementation and pass the
+ * control vaules manually.
+ */
+abstract class RecursiveFilterIterator extends FilterIterator implements RecursiveIterator
+{
+ /** @param $it the RecursiveIterator to filter
+ */
+ function __construct(RecursiveIterator $it)
+ {
+ parent::__construct($it);
+ }
+
+ /** @return whether the current element has children
+ */
+ function hasChildren()
+ {
+ return $this->getInnerIterator()->hasChildren();
+ }
+
+ /** @return an iterator for the current elements children
+ *
+ * @note the returned iterator will be of the same class as $this
+ */
+ function getChildren()
+ {
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance($this->getInnerIterator()->getChildren());
+ }
+
+ private $ref;
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursiveiterator.inc b/ext/spl/internal/recursiveiterator.inc
new file mode 100644
index 0000000..1eab3d6
--- /dev/null
+++ b/ext/spl/internal/recursiveiterator.inc
@@ -0,0 +1,30 @@
+<?php
+
+/** @file recursiveiterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Interface for recursive iteration with RecursiveIteratorIterator
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.0
+ */
+interface RecursiveIterator extends Iterator
+{
+ /** @return whether the current element has children
+ */
+ function hasChildren();
+
+ /** @return the sub iterator for the current element
+ * @note The returned object must implement RecursiveIterator.
+ */
+ function getChildren();
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursiveiteratoriterator.inc b/ext/spl/internal/recursiveiteratoriterator.inc
new file mode 100644
index 0000000..35fa801
--- /dev/null
+++ b/ext/spl/internal/recursiveiteratoriterator.inc
@@ -0,0 +1,237 @@
+<?php
+
+/** @file recursiveiteratoriterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveIteratorIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Iterates through recursive iterators
+ * @author Marcus Boerger
+ * @version 1.2
+ * @since PHP 5.0
+ *
+ * The objects of this class are created by instances of RecursiveIterator.
+ * Elements of those iterators may be traversable themselves. If so these
+ * sub elements are recursed into.
+ */
+class RecursiveIteratorIterator implements OuterIterator
+{
+ /** Mode: Only show leaves */
+ const LEAVES_ONLY = 0;
+ /** Mode: Show parents prior to their children */
+ const SELF_FIRST = 1;
+ /** Mode: Show all children prior to their parent */
+ const CHILD_FIRST = 2;
+
+ /** Flag: Catches exceptions during getChildren() calls and simply jumps
+ * to the next element. */
+ const CATCH_GET_CHILD = 0x00000002;
+
+ private $ait = array();
+ private $count = 0;
+ private $mode = self::LEAVES_ONLY;
+ private $flags = 0;
+
+ /** Construct from RecursiveIterator
+ *
+ * @param it RecursiveIterator to iterate
+ * @param mode Operation mode (one of):
+ * - LEAVES_ONLY only show leaves
+ * - SELF_FIRST show parents prior to their childs
+ * - CHILD_FIRST show all children prior to their parent
+ * @param flags Control flags, zero or any combination of the following
+ * (since PHP 5.1).
+ * - CATCH_GET_CHILD which catches exceptions during
+ * getChildren() calls and simply jumps to the next
+ * element.
+ */
+ function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0)
+ {
+ $this->ait[0] = $it;
+ $this->mode = $mode;
+ $this->flags = $flags;
+ }
+
+ /** Rewind to top iterator as set in constructor
+ */
+ function rewind()
+ {
+ while ($this->count) {
+ unset($this->ait[$this->count--]);
+ $this->endChildren();
+ }
+ $this->ait[0]->rewind();
+ $this->ait[0]->recursed = false;
+ callNextElement(true);
+ }
+
+ /** @return whether iterator is valid
+ */
+ function valid()
+ {
+ $count = $this->count;
+ while ($count) {
+ $it = $this->ait[$count];
+ if ($it->valid()) {
+ return true;
+ }
+ $count--;
+ $this->endChildren();
+ }
+ return false;
+ }
+
+ /** @return current key
+ */
+ function key()
+ {
+ $it = $this->ait[$this->count];
+ return $it->key();
+ }
+
+ /** @return current element
+ */
+ function current()
+ {
+ $it = $this->ait[$this->count];
+ return $it->current();
+ }
+
+ /** Forward to next element
+ */
+ function next()
+ {
+ while ($this->count) {
+ $it = $this->ait[$this->count];
+ if ($it->valid()) {
+ if (!$it->recursed && callHasChildren()) {
+ $it->recursed = true;
+ try
+ {
+ $sub = callGetChildren();
+ }
+ catch (Exception $e)
+ {
+ if (!($this->flags & self::CATCH_GET_CHILD))
+ {
+ throw $e;
+ }
+ $it->next();
+ continue;
+ }
+ $sub->recursed = false;
+ $sub->rewind();
+ if ($sub->valid()) {
+ $this->ait[++$this->count] = $sub;
+ if (!$sub instanceof RecursiveIterator) {
+ throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator');
+ }
+ $this->beginChildren();
+ return;
+ }
+ unset($sub);
+ }
+ $it->next();
+ $it->recursed = false;
+ if ($it->valid()) {
+ return;
+ }
+ $it->recursed = false;
+ }
+ if ($this->count) {
+ unset($this->ait[$this->count--]);
+ $it = $this->ait[$this->count];
+ $this->endChildren();
+ callNextElement(false);
+ }
+ }
+ callNextElement(true);
+ }
+
+ /** @return Sub Iterator at given level or if unspecified the current sub
+ * Iterator
+ */
+ function getSubIterator($level = NULL)
+ {
+ if (is_null($level)) {
+ $level = $this->count;
+ }
+ return @$this->ait[$level];
+ }
+
+ /**
+ * @return The inner iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->it;
+ }
+
+ /** @return Current Depth (Number of parents)
+ */
+ function getDepth()
+ {
+ return $this->level;
+ }
+
+ /** @return whether current sub iterators current element has children
+ * @since PHP 5.1
+ */
+ function callHasChildren()
+ {
+ return $this->ait[$this->count]->hasChildren();
+ }
+
+ /** @return current sub iterators current children
+ * @since PHP 5.1
+ */
+ function callGetChildren()
+ {
+ return $this->ait[$this->count]->getChildren();
+ }
+
+ /** Called right after calling getChildren() and its rewind().
+ * @since PHP 5.1
+ */
+ function beginChildren()
+ {
+ }
+
+ /** Called after current child iterator is invalid and right before it
+ * gets destructed.
+ * @since PHP 5.1
+ */
+ function endChildren()
+ {
+ }
+
+ private function callNextElement($after_move)
+ {
+ if ($this->valid())
+ {
+ if ($after_move)
+ {
+ if (($this->mode == self::SELF_FIRST && $this->callHasChildren())
+ || $this->mode == self::LEAVES_ONLY)
+ $this->nextElement();
+ }
+ else
+ {
+ $this->nextElement();
+ }
+ }
+ }
+
+ /** Called when the next element is available
+ */
+ function nextElement()
+ {
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursiveregexiterator.inc b/ext/spl/internal/recursiveregexiterator.inc
new file mode 100644
index 0000000..ffcff0c
--- /dev/null
+++ b/ext/spl/internal/recursiveregexiterator.inc
@@ -0,0 +1,61 @@
+<?php
+
+/** @file recursiveregexiterator.inc
+ * @ingroup SPL
+ * @brief class RegexIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Recursive regular expression filter for iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * This filter iterator assumes that the inner iterator
+ */
+class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator
+{
+ /**
+ * Constructs a regular expression filter around an iterator whose
+ * elemnts or keys are strings.
+ *
+ * @param it inner iterator
+ * @param regex the regular expression to match
+ * @param mode operation mode (one of self::MATCH, self::GET_MATCH,
+ * self::ALL_MATCHES, self::SPLIT)
+ * @param flags special flags (self::USE_KEY)
+ * @param preg_flags global PREG_* flags, see preg_match(),
+ * preg_match_all(), preg_split()
+ */
+ function __construct(RecursiveIterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) {
+ parent::__construct($it, $regex, $mode, $flags, $preg_flags);
+ }
+
+ /** @return whether the current element has children
+ */
+ function hasChildren()
+ {
+ return $this->getInnerIterator()->hasChildren();
+ }
+
+ /** @return an iterator for the current elements children
+ *
+ * @note the returned iterator will be of the same class as $this
+ */
+ function getChildren()
+ {
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance($this->getInnerIterator()->getChildren());
+ }
+
+ private $ref;
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/recursivetreeiterator.inc b/ext/spl/internal/recursivetreeiterator.inc
new file mode 100644
index 0000000..dfcdc05
--- /dev/null
+++ b/ext/spl/internal/recursivetreeiterator.inc
@@ -0,0 +1,132 @@
+<?php
+
+/** @file recursivetreeiterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveTreeIterator
+ * @author Marcus Boerger, Johannes Schlueter
+ * @date 2005 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+
+/** @ingroup SPL
+ * @brief RecursiveIteratorIterator to generate ASCII graphic trees for the
+ * entries in a RecursiveIterator
+ * @author Marcus Boerger, Johannes Schlueter
+ * @version 1.1
+ * @since PHP 5.3
+ */
+class RecursiveTreeIterator extends RecursiveIteratorIterator
+{
+ const BYPASS_CURRENT = 0x00000004;
+ const BYPASS_KEY = 0x00000008;
+
+ private $rit_flags;
+
+ /**
+ * @param it iterator to use as inner iterator
+ * @param rit_flags flags passed to RecursiveIteratoIterator (parent)
+ * @param cit_flags flags passed to RecursiveCachingIterator (for hasNext)
+ * @param mode mode passed to RecursiveIteratoIterator (parent)
+ */
+ function __construct(RecursiveIterator $it, $rit_flags = self::BYPASS_KEY, $cit_flags = CachingIterator::CATCH_GET_CHILD, $mode = self::SELF_FIRST)
+ {
+ parent::__construct(new RecursiveCachingIterator($it, $cit_flags), $mode, $rit_flags);
+ $this->rit_flags = $rit_flags;
+ }
+
+ private $prefix = array(0=>'', 1=>'| ', 2=>' ', 3=>'|-', 4=>'\-', 5=>'');
+
+ /** Prefix used to start elements. */
+ const PREFIX_LEFT = 0;
+ /** Prefix used if $level < depth and hasNext($level) == true. */
+ const PREFIX_MID_HAS_NEXT = 1;
+ /** Prefix used if $level < depth and hasNext($level) == false. */
+ const PREFIX_MID_LAST = 2;
+ /** Prefix used if $level == depth and hasNext($level) == true. */
+ const PREFIX_END_HAS_NEXT = 3;
+ /** Prefix used if $level == depth and hasNext($level) == false. */
+ const PREFIX_END_LAST = 4;
+ /** Prefix used right in front of the current element. */
+ const PREFIX_RIGHT = 5;
+
+ /**
+ * Set prefix part as used in getPrefix() and stored in $prefix.
+ * @param $part any PREFIX_* const.
+ * @param $value new prefix string for specified part.
+ * @throws OutOfRangeException if 0 > $part or $part > 5.
+ */
+ function setPrefixPart($part, $value)
+ {
+ if (0 > $part || $part > 5) {
+ throw new OutOfRangeException();
+ }
+ $this->prefix[$part] = (string)$value;
+ }
+
+ /** @return string to place in front of current element
+ */
+ function getPrefix()
+ {
+ $tree = '';
+ for ($level = 0; $level < $this->getDepth(); $level++)
+ {
+ $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[1] : $this->prefix[2];
+ }
+ $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[3] : $this->prefix[4];
+
+ return $this->prefix[0] . $tree . $this->prefix[5];
+ }
+
+ /** @return string presentation build for current element
+ */
+ function getEntry()
+ {
+ return @(string)parent::current();
+ }
+
+ /** @return string to place after the current element
+ */
+ function getPostfix()
+ {
+ return '';
+ }
+
+ /** @return the current element prefixed and postfixed
+ */
+ function current()
+ {
+ if ($this->rit_flags & self::BYPASS_CURRENT)
+ {
+ return parent::current();
+ }
+ else
+ {
+ return $this->getPrefix() . $this->getEntry() . $this->getPostfix();
+ }
+ }
+
+ /** @return the current key prefixed and postfixed
+ */
+ function key()
+ {
+ if ($this->rit_flags & self::BYPASS_KEY)
+ {
+ return parent::key();
+ }
+ else
+ {
+ return $this->getPrefix() . parent::key() . $this->getPostfix();
+ }
+ }
+
+ /** Aggregates the inner iterator
+ */
+ function __call($func, $params)
+ {
+ return call_user_func_array(array($this->getSubIterator(), $func), $params);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/regexiterator.inc b/ext/spl/internal/regexiterator.inc
new file mode 100644
index 0000000..c6addb9
--- /dev/null
+++ b/ext/spl/internal/regexiterator.inc
@@ -0,0 +1,170 @@
+<?php
+
+/** @file regexiterator.inc
+ * @ingroup SPL
+ * @brief class RegexIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Regular expression filter for iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * This filter iterator assumes that the inner iterator
+ */
+class RegexIterator extends FilterIterator
+{
+ const USE_KEY = 0x00000001; /**< If present in $flags the key is
+ used rather then the current value. */
+
+ const MATCH = 0; /**< Mode: Executed a plain match only */
+ const GET_MATCH = 1; /**< Mode: Return the first matche (if any) */
+ const ALL_MATCHES = 2; /**< Mode: Return all matches (if any) */
+ const SPLIT = 3; /**< Mode: Return the split values (if any) */
+ const REPLACE = 4; /**< Mode: Replace the input key or current */
+
+ private $regex; /**< the regular expression to match against */
+ private $mode; /**< operation mode (one of self::MATCH,
+ self::GET_MATCH, self::ALL_MATCHES, self::SPLIT) */
+ private $flags; /**< special flags (self::USE_KEY) */
+ private $preg_flags;/**< PREG_* flags, see preg_match(), preg_match_all(),
+ preg_split() */
+ private $key; /**< the value used for key() */
+ private $current; /**< the value used for current() */
+
+ /**
+ * Constructs a regular expression filter around an iterator whose
+ * elemnts or keys are strings.
+ *
+ * @param it inner iterator
+ * @param regex the regular expression to match
+ * @param mode operation mode (one of self::MATCH, self::GET_MATCH,
+ * self::ALL_MATCHES, self::SPLIT)
+ * @param flags special flags (self::USE_KEY)
+ * @param preg_flags global PREG_* flags, see preg_match(),
+ * preg_match_all(), preg_split()
+ */
+ function __construct(Iterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) {
+ parent::__construct($it);
+ $this->regex = $regex;
+ $this->flags = $flags;
+ $this->mode = $mode;
+ $this->preg_flags = $preg_flags;
+ }
+
+ /**
+ * Match current or key against regular expression using mode, flags and
+ * preg_flags.
+ *
+ * @return whether this is a match
+ *
+ * @warning never call this twice for the same state
+ */
+ function accept()
+ {
+ $matches = array();
+ $this->key = parent::key();
+ $this->current = parent::current();
+ /* note that we use $this->current, rather than calling parent::current() */
+ $subject = ($this->flags & self::USE_KEY) ? $this->key : $this->current;
+ switch($this->mode)
+ {
+ case self::MATCH:
+ return preg_match($this->regex, $subject, $matches, $this->preg_flags);
+
+ case self::GET_MATCH:
+ $this->current = array();
+ return preg_match($this->regex, $subject, $this->current, $this->preg_flags) > 0;
+
+ case self::ALL_MATCHES:
+ $this->current = array();
+ return preg_match_all($this->regex, $subject, $this->current, $this->preg_flags) > 0;
+
+ case self::SPLIT:
+ $this->current = array();
+ preg_split($this->regex, $subject, $this->current, $this->preg_flags) > 1;
+
+ case self::REPLACE:
+ $this->current = array();
+ $result = preg_replace($this->regex, $this->replacement, $subject);
+ if ($this->flags & self::USE_KEY)
+ {
+ $this->key = $result;
+ }
+ else
+ {
+ $this->current = $result;
+ }
+ }
+ }
+
+ /** @return the key after accept has been called
+ */
+ function key()
+ {
+ return $this->key;
+ }
+
+ /** @return the current value after accept has been called
+ */
+ function current()
+ {
+ return $this->current;
+ }
+
+ /** @return current operation mode
+ */
+ function getMode()
+ {
+ return $this->mode;
+ }
+
+ /** @param mode new operaion mode
+ */
+ function setMode($mode)
+ {
+ $this->mode = $mode;
+ }
+
+ /** @return current operation flags
+ */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** @param flags new operaion flags
+ */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /** @return current PREG flags
+ */
+ function getPregFlags()
+ {
+ return $this->preg_flags;
+ }
+
+ /** @param preg_flags new PREG flags
+ */
+ function setPregFlags($preg_flags)
+ {
+ $this->preg_flags = $preg_flags;
+ }
+
+ /** @return current regular expression
+ */
+ function getRegex()
+ {
+ return $this->regex;
+ }
+}
+
+?>
diff --git a/ext/spl/internal/seekableiterator.inc b/ext/spl/internal/seekableiterator.inc
new file mode 100644
index 0000000..b4f66bd
--- /dev/null
+++ b/ext/spl/internal/seekableiterator.inc
@@ -0,0 +1,48 @@
+<?php
+
+/** @file seekableiterator.inc
+ * @ingroup SPL
+ * @brief class SeekableIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @brief seekable iterator
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.0
+ *
+ * Turns a normal iterator ino a seekable iterator. When there is a way
+ * to seek on an iterator LimitIterator can use this to efficiently rewind
+ * to offset.
+ */
+interface SeekableIterator extends Iterator
+{
+ /** Seek to an absolute position
+ *
+ * \param $index position to seek to
+ * \return void
+ *
+ * The method should throw an exception if it is not possible to seek to
+ * the given position. Typically this exception should be of type
+ * OutOfBoundsException.
+ \code
+ function seek($index);
+ $this->rewind();
+ $position = 0;
+ while($position < $index && $this->valid()) {
+ $this->next();
+ $position++;
+ }
+ if (!$this->valid()) {
+ throw new OutOfBoundsException('Invalid seek position');
+ }
+ }
+ \endcode
+ */
+ function seek($index);
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/spldoublylinkedlist.inc b/ext/spl/internal/spldoublylinkedlist.inc
new file mode 100644
index 0000000..e87e4b1
--- /dev/null
+++ b/ext/spl/internal/spldoublylinkedlist.inc
@@ -0,0 +1,277 @@
+<?php
+/** @file spldoublylinkedlist.inc
+ * @ingroup SPL
+ * @brief class SplDoublyLinkedList
+ * @author Etienne Kneuss
+ * @date 2008 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Doubly Linked List
+ * @since PHP 5.3
+ *
+ * The SplDoublyLinkedList class provides the main functionalities of a
+ * doubly linked list (DLL).
+ * @note The following userland implementation of Iterator is a bit different
+ * from the internal one. Internally, iterators generated by nested
+ * foreachs are independent, while they share the same traverse pointer
+ * in userland.
+ */
+class SplDoublyLinkedList implements Iterator, ArrayAccess, Countable
+{
+ protected $_llist = array();
+ protected $_it_mode = 0;
+ protected $_it_pos = 0;
+
+ /** Iterator mode
+ * @see setIteratorMode
+ */
+ const IT_MODE_LIFO = 0x00000002;
+
+ /** Iterator mode
+ * @see setIteratorMode
+ */
+ const IT_MODE_FIFO = 0x00000000;
+
+ /** Iterator mode
+ * @see setIteratorMode
+ */
+ const IT_MODE_KEEP = 0x00000000;
+
+ /** Iterator mode
+ * @see setIteratorMode
+ */
+ const IT_MODE_DELETE = 0x00000001;
+
+ /** @return the element popped from the end of the DLL.
+ * @throw RuntimeException If the datastructure is empty.
+ */
+ public function pop()
+ {
+ if (count($this->_llist) == 0) {
+ throw new RuntimeException("Can't pop from an empty datastructure");
+ }
+ return array_pop($this->_llist);
+ }
+
+ /** @return the element shifted from the beginning of the DLL.
+ * @throw RuntimeException If the datastructure is empty.
+ */
+ public function shift()
+ {
+ if (count($this->_llist) == 0) {
+ throw new RuntimeException("Can't shift from an empty datastructure");
+ }
+ return array_shift($this->_llist);
+ }
+
+ /** Pushes an element to the end of the DLL.
+ * @param $data variable to add to the DLL.
+ */
+ public function push($data)
+ {
+ array_push($this->_llist, $data);
+ return true;
+ }
+
+ /** Adds an element to the beginning of the DLL.
+ * @param $data variable to add to the DLL.
+ */
+ public function unshift($data)
+ {
+ array_unshift($this->_llist, $data);
+ return true;
+ }
+
+ /** @return the element at the beginning of the DLL.
+ */
+ public function top()
+ {
+ return end($this->_llist);
+ }
+
+ /** @return the element at the end of the DLL.
+ */
+ public function bottom()
+ {
+ return reset($this->_llist);
+ }
+
+ /** @return number elements in the DLL.
+ */
+ public function count()
+ {
+ return count($this->_llist);
+ }
+
+ /** @return whether the DLL is empty.
+ */
+ public function isEmpty()
+ {
+ return ($this->count() == 0);
+ }
+
+ /** Changes the iteration mode. There are two orthogonal sets of modes that
+ * can be set:
+ * - The direction of the iteration (either one or the other)
+ * - SplDoublyLnkedList::IT_MODE_LIFO (Stack style)
+ * - SplDoublyLnkedList::IT_MODE_FIFO (Queue style)
+ *
+ * - The behavior of the iterator (either one or the other)
+ * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator)
+ * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator)
+ *
+ * The default mode is 0 : SplDoublyLnkedList::IT_MODE_FIFO | SplDoublyLnkedList::IT_MODE_KEEP
+ *
+ * @param $mode new mode of iteration
+ */
+ public function setIteratorMode($mode)
+ {
+ $this->_it_mode = $mode;
+ }
+
+ /** @return the current iteration mode
+ * @see setIteratorMode
+ */
+ public function getIteratorMode()
+ {
+ return $this->_it_mode;
+ }
+
+ /** Rewind to top iterator as set in constructor
+ */
+ public function rewind()
+ {
+ if ($this->_it_mode & self::IT_MODE_LIFO) {
+ $this->_it_pos = count($this->_llist)-1;
+ } else {
+ $this->_it_pos = 0;
+ }
+ }
+
+ /** @return whether iterator is valid
+ */
+ public function valid()
+ {
+ return array_key_exists($this->_it_pos, $this->_llist);
+ }
+
+ /** @return current key
+ */
+ public function key()
+ {
+ return $this->_it_pos;
+ }
+
+ /** @return current object
+ */
+ public function current()
+ {
+ return $this->_llist[$this->_it_pos];
+ }
+
+ /** Forward to next element
+ */
+ public function next()
+ {
+ if ($this->_it_mode & self::IT_MODE_LIFO) {
+ if ($this->_it_mode & self::IT_MODE_DELETE) {
+ $this->pop();
+ }
+ $this->_it_pos--;
+ } else {
+ if ($this->_it_mode & self::IT_MODE_DELETE) {
+ $this->shift();
+ } else {
+ $this->_it_pos++;
+ }
+ }
+ }
+
+ /** @return whether a certain offset exists in the DLL
+ *
+ * @param $offset The offset
+ * @throw OutOfRangeException If the offset is either invalid or out of
+ * range.
+ */
+ public function offsetExists($offset)
+ {
+ if (!is_numeric($offset)) {
+ throw new OutOfRangeException("Offset invalid or out of range");
+ } else {
+ return array_key_exists($offset, $this->_llist);
+ }
+ }
+
+ /** @return the data at a certain offset in the DLL
+ *
+ * @param $offset The offset
+ * @throw OutOfRangeException If the offset is either invalid or out of
+ * range.
+ */
+ public function offsetGet($offset)
+ {
+ if ($this->_it_mode & self::IT_MODE_LIFO) {
+ $realOffset = count($this->_llist)-$offset;
+ } else {
+ $realOffset = $offset;
+ }
+
+ if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
+ throw new OutOfRangeException("Offset invalid or out of range");
+ } else {
+ return $this->_llist[$realOffset];
+ }
+ }
+
+ /** Defines the data at a certain offset in the DLL
+ *
+ * @param $offset The offset
+ * @param $value New value
+ * @throw OutOfRangeException If the offset is either invalid or out of
+ * range.
+ */
+ public function offsetSet($offset, $value)
+ {
+ if ($offset === null) {
+ return $this->push($value);
+ }
+
+ if ($this->_it_mode & self::IT_MODE_LIFO) {
+ $realOffset = count($this->_llist)-$offset;
+ } else {
+ $realOffset = $offset;
+ }
+
+ if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
+ throw new OutOfRangeException("Offset invalid or out of range");
+ } else {
+ $this->_llist[$realOffset] = $value;
+ }
+ }
+
+ /** Unsets the element at a certain offset in the DLL
+ *
+ * @param $offset The offset
+ * @throw OutOfRangeException If the offset is either invalid or out of
+ * range.
+ */
+ public function offsetUnset($offset)
+ {
+ if ($this->_it_mode & self::IT_MODE_LIFO) {
+ $realOffset = count($this->_llist)-$offset;
+ } else {
+ $realOffset = $offset;
+ }
+
+ if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) {
+ throw new OutOfRangeException("Offset invalid or out of range");
+ } else {
+ array_splice($this->_llist, $realOffset, 1);
+ }
+ }
+}
+
+?>
diff --git a/ext/spl/internal/splfileobject.inc b/ext/spl/internal/splfileobject.inc
new file mode 100644
index 0000000..46b941f
--- /dev/null
+++ b/ext/spl/internal/splfileobject.inc
@@ -0,0 +1,377 @@
+<?php
+
+/** @file splfileobject.inc
+ * @ingroup SPL
+ * @brief class FileObject
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Object representation for any stream
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.1
+ */
+class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator
+{
+ /** Flag: wheter to suppress new lines */
+ const DROP_NEW_LINE = 0x00000001;
+
+ private $fp;
+ private $fname;
+ private $line = NULL;
+ private $lnum = 0;
+ private $max_len = 0;
+ private $flags = 0;
+ private $delimiter= ',';
+ private $enclosure= '"';
+
+ /**
+ * Constructs a new file object
+ *
+ * @param $file_name The name of the stream to open
+ * @param $open_mode The file open mode
+ * @param $use_include_path Whether to search in include paths
+ * @param $context A stream context
+ * @throw RuntimeException If file cannot be opened (e.g. insufficient
+ * access rights).
+ */
+ function __construct($file_name, $open_mode = 'r', $use_include_path = false, $context = NULL)
+ {
+ $this->fp = fopen($file_name, $open_mode, $use_include_path, $context);
+ if (!$this->fp)
+ {
+ throw new RuntimeException("Cannot open file $file_name");
+ }
+ $this->fname = $file_name;
+ }
+
+ /**
+ * @return whether the end of the stream is reached
+ */
+ function eof()
+ {
+ return eof($this->fp);
+ }
+
+ /** increase current line number
+ * @return next line from stream
+ */
+ function fgets()
+ {
+ $this->freeLine();
+ $this->lnum++;
+ $buf = fgets($this->fp, $this->max_len);
+
+ return $buf;
+ }
+
+ /**
+ * @param delimiter character used as field separator
+ * @param enclosure end of
+ * @return array containing read data
+ */
+ function fgetcsv($delimiter = NULL, $enclosure = NULL)
+ {
+ $this->freeLine();
+ $this->lnum++;
+ switch(fun_num_args())
+ {
+ case 0:
+ $delimiter = $this->delimiter;
+ case 1:
+ $enclosure = $this->enclosure;
+ default:
+ case 2:
+ break;
+ }
+ return fgetcsv($this->fp, $this->max_len, $delimiter, $enclosure);
+ }
+
+ /**
+ * Set the delimiter and enclosure character used in fgetcsv
+ *
+ * @param delimiter new delimiter, defaults to ','
+ * @param enclosure new enclosure, defaults to '"'
+ */
+ function setCsvControl($delimiter = ';', $enclosure = '"')
+ {
+ $this->delimiter = $delimiter;
+ $this->enclosure = $enclosure;
+ }
+
+ /**
+ * @return array(delimiter, enclosure) as used in fgetcsv
+ */
+ function getCsvControl($delimiter = ',', $enclosure = '"')
+ {
+ return array($this->delimiter, $this->enclosure);
+ }
+
+ /**
+ * @param operation lock operation (LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB)
+ * @retval $wouldblock whether the operation would block
+ */
+ function flock($operation, &$wouldblock)
+ {
+ return flock($this->fp, $operation, $wouldblock);
+ }
+
+ /**
+ * Flush current data
+ * @return success or failure
+ */
+ function fflush()
+ {
+ return fflush($this->fp);
+ }
+
+ /**
+ * @return current file position
+ */
+ function ftell()
+ {
+ return ftell($this->fp);
+ }
+
+ /**
+ * @param pos new file position
+ * @param whence seek method (SEEK_SET, SEEK_CUR, SEEK_END)
+ * @return Upon success, returns 0; otherwise, returns -1. Note that
+ * seeking past EOF is not considered an error.
+ */
+ function fseek($pos, $whence = SEEK_SET)
+ {
+ return fseek($this->fp, $pos, $whence);
+ }
+
+ /**
+ * @return next char from file
+ * @note a new line character does not increase $this->lnum
+ */
+ function fgetc()
+ {
+ $this->freeLine();
+ $c = fgetc($this->fp);
+ if ($c == '\n') {
+ $this->lnum++;
+ }
+ }
+
+ /** Read and return remaining part of stream
+ * @return size of remaining part passed through
+ */
+ function fpassthru()
+ {
+ return fpassthru($this->fp);
+ }
+
+ /** Get a line from the file and strip HTML tags
+ * @param $allowable_tags tags to keep in the string
+ */
+ function fgetss($allowable_tags = NULL)
+ {
+ return fgetss($this->fp, $allowable_tags);
+ }
+
+ /** Scan the next line
+ * @param $format string specifying format to parse
+ */
+ function fscanf($format /* , ... */)
+ {
+ $this->freeLine();
+ $this->lnum++;
+ return fscanf($this->fp, $format /* , ... */);
+ }
+
+ /**
+ * @param $str to write
+ * @param $length maximum line length to write
+ */
+ function fwrite($str, $length = NULL)
+ {
+ return fwrite($this->fp, $length);
+ }
+
+ /**
+ * @return array of file stat information
+ */
+ function fstat()
+ {
+ return fstat($this->fp);
+ }
+
+ /**
+ * @param $size new size to truncate file to
+ */
+ function ftruncate($size)
+ {
+ return ftruncate($this->fp, $size);
+ }
+
+ /**
+ * @param $flags new flag set
+ */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * @return current set of flags
+ */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * @param $max_len set the maximum line length read
+ */
+ function setMaxLineLen($max_len)
+ {
+ $this->max_len = $max_len;
+ }
+
+ /**
+ * @return current setting for max line
+ */
+ function getMaxLineLen()
+ {
+ return $this->max_len;
+ }
+
+ /**
+ * @return false
+ */
+ function hasChildren()
+ {
+ return false;
+ }
+
+ /**
+ * @return false
+ */
+ function getChildren()
+ {
+ return NULL;
+ }
+
+ /**
+ * Invalidate current line buffer and set line number to 0.
+ */
+ function rewind()
+ {
+ $this->freeLine();
+ $this->lnum = 0;
+ }
+
+ /**
+ * @return whether more data can be read
+ */
+ function valid()
+ {
+ return !$this->eof();
+ }
+
+ /**
+ * @note Fill current line buffer if not done yet.
+ * @return line buffer
+ */
+ function current()
+ {
+ if (is_null($this->line))
+ {
+ $this->line = getCurrentLine();
+ }
+ return $this->line;
+ }
+
+ /**
+ * @return line number
+ * @note fgetc() will increase the line number when reaing a new line char.
+ * This has the effect key() called on a read a new line will already
+ * return the increased line number.
+ * @note Line counting works as long as you only read the file and do not
+ * use fseek().
+ */
+ function key()
+ {
+ return $this->lnum;
+ }
+
+ /** Invalidate current line buffer.
+ */
+ function next()
+ {
+ $this->freeLine();
+ }
+
+ /**
+ * @return next line read from file and increase the line counter
+ */
+ private function readLine()
+ {
+ if ($this->eof())
+ {
+ $this->freeLine();
+ throw new RuntimeException("Cannot read from file " . $this->fname);
+ }
+ if ($this->line) {
+ $this->lnum++;
+ }
+ $this->freeLine();
+ $this->line = fgets($this->fp, $this->max_len);
+ return $this->line;
+ }
+
+ /**
+ * Free the current line buffer and increment the line counter
+ */
+ private function freeLine()
+ {
+ if ($this->line) {
+ $this->line = NULL;
+ }
+ }
+
+ /*
+ * @note If you DO overload this function key() and current() will increment
+ * $this->lnum automatically. If not then function reaLine() will do
+ * that for you.
+ */
+ function getCurrentLine()
+ {
+ $this->freeLine();
+ if ($this->eof())
+ {
+ throw new RuntimeException("Cannot read from file " . $this->fname);
+ }
+ $this->readLine();
+ }
+
+ /**
+ * @return current line
+ */
+ function __toString()
+ {
+ return current();
+ }
+
+ /**
+ * @param $line_pos Seek to this line
+ */
+ function seek($line_pos)
+ {
+ $this->rewind();
+ while($this->lnum < $line_pos && !$this->eof())
+ {
+ $this->getCurrentLine();
+ }
+ }
+}
+
+?>
diff --git a/ext/spl/internal/splobjectstorage.inc b/ext/spl/internal/splobjectstorage.inc
new file mode 100644
index 0000000..fa16406
--- /dev/null
+++ b/ext/spl/internal/splobjectstorage.inc
@@ -0,0 +1,188 @@
+<?php
+
+/** @file splobjectstorage.inc
+ * @ingroup SPL
+ * @brief class SplObjectStorage
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Object storage
+ * @author Marcus Boerger
+ * @version 1.1
+ * @since PHP 5.1.2
+ *
+ * This container allows to store objects uniquly without the need to compare
+ * them one by one. This is only possible internally. The code represenation
+ * here therefore has a complexity of O(n) while the actual implementation has
+ * complexity O(1).
+ */
+class SplObjectStorage implements Iterator, Countable, ArrayAccess
+{
+ private $storage = array();
+ private $index = 0;
+
+ /** Rewind to top iterator as set in constructor
+ */
+ function rewind()
+ {
+ rewind($this->storage);
+ }
+
+ /** @return whether iterator is valid
+ */
+ function valid()
+ {
+ return key($this->storage) !== false;
+ }
+
+ /** @return current key
+ */
+ function key()
+ {
+ return $this->index;
+ }
+
+ /** @return current object
+ */
+ function current()
+ {
+ $element = current($this->storage);
+ return $element ? $element[0] : NULL
+ }
+
+ /** @return get current object's associated information
+ * @since 5.3.0
+ */
+ function getInfo()
+ {
+ $element = current($this->storage);
+ return $element ? $element[1] : NULL
+ }
+
+ /** @return set current object's associated information
+ * @since 5.3.0
+ */
+ function setInfo($inf = NULL)
+ {
+ if ($this->valid()) {
+ $this->storage[$this->index][1] = $inf;
+ }
+ }
+
+ /** Forward to next element
+ */
+ function next()
+ {
+ next($this->storage);
+ $this->index++;
+ }
+
+ /** @return number of objects in storage
+ */
+ function count()
+ {
+ return count($this->storage);
+ }
+
+ /** @param $obj object to look for
+ * @return whether $obj is contained in storage
+ */
+ function contains($obj)
+ {
+ if (is_object($obj))
+ {
+ foreach($this->storage as $element)
+ {
+ if ($object === $element[0])
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /** @param $obj new object to attach to storage or object whose
+ * associative information is to be replaced
+ * @param $inf associative information stored along the object
+ */
+ function attach($obj, $inf = NULL)
+ {
+ if (is_object($obj) && !$this->contains($obj))
+ {
+ $this->storage[] = array($obj, $inf);
+ }
+ }
+
+ /** @param $obj object to remove from storage
+ */
+ function detach($obj)
+ {
+ if (is_object($obj))
+ {
+ foreach($this->storage as $idx => $element)
+ {
+ if ($object === $element[0])
+ {
+ unset($this->storage[$idx]);
+ $this->rewind();
+ return;
+ }
+ }
+ }
+ }
+
+ /** @param $obj new object to attach to storage or object whose
+ * associative information is to be replaced
+ * @param $inf associative information stored along the object
+ * @since 5.3.0
+ */
+ function offsetSet($obj, $inf)
+ {
+ $this->attach($obj, $inf);
+ }
+
+ /** @param $obj Exising object to look for
+ * @return associative information stored with object
+ * @throw UnexpectedValueException if Object $obj is not contained in
+ * storage
+ * @since 5.3.0
+ */
+ function offsetGet($obj)
+ {
+ if (is_object($obj))
+ {
+ foreach($this->storage as $idx => $element)
+ {
+ if ($object === $element[0])
+ {
+ return $element[1];
+ }
+ }
+ }
+ throw new UnexpectedValueException('Object not found');
+ }
+
+ /** @param $obj Exising object to look for
+ * @return associative information stored with object
+ * @since 5.3.0
+ */
+ function offsetUnset($obj)
+ {
+ $this->detach($obj);
+ }
+
+ /** @param $obj object to look for
+ * @return whether $obj is contained in storage
+ */
+ function offsetEsists($obj)
+ {
+ return $this->contains($obj);
+ }
+}
+
+?>
diff --git a/ext/spl/internal/splqueue.inc b/ext/spl/internal/splqueue.inc
new file mode 100644
index 0000000..368a259
--- /dev/null
+++ b/ext/spl/internal/splqueue.inc
@@ -0,0 +1,71 @@
+<?php
+
+/** @file splqueue.inc
+ * @ingroup SPL
+ * @brief class SplQueue
+ * @author Etienne Kneuss
+ * @date 2008 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Implementation of a Queue through a DoublyLinkedList. As SplQueue
+ * extends SplDoublyLinkedList, unshift() and pop() are still available
+ * even though they don't make much sense for a queue. For convenience,
+ * two aliases are available:
+ * - enqueue() is an alias of push()
+ * - dequeue() is an alias of shift()
+ *
+ * @since PHP 5.3
+ *
+ * The SplQueue class provides the main functionalities of a
+ * queue implemented using a doubly linked list (DLL).
+ */
+class SplQueue extends SplDoublyLinkedList
+{
+ protected $_it_mode = parent::IT_MODE_FIFO;
+
+ /** Changes the iteration mode. There are two orthogonal sets of modes that
+ * can be set:
+ *
+ * - The behavior of the iterator (either one or the other)
+ * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator)
+ * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator)
+ *
+ * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP
+ *
+ * @note The iteration's direction is not modifiable for queue instances
+ * @param $mode New mode of iteration
+ * @throw RuntimeException If the new mode affects the iteration's direction.
+ */
+ public function setIteratorMode($mode)
+ {
+ if ($mode & parent::IT_MODE_LIFO === parent::IT_MODE_LIFO) {
+ throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen");
+ }
+
+ $this->_it_mode = $mode;
+ }
+
+ /** @return the first element of the queue.
+ * @note dequeue is an alias of push()
+ * @see splDoublyLinkedList::push()
+ */
+ public function dequeue()
+ {
+ return parent::shift();
+ }
+
+ /** Pushes an element at the end of the queue.
+ * @param $data variable to add to the queue.
+ * @note enqueue is an alias of shift()
+ * @see splDoublyLinkedList::shift()
+ */
+ public function enqueue($data)
+ {
+ return parent::push($data);
+ }
+}
+
+?>
diff --git a/ext/spl/internal/splstack.inc b/ext/spl/internal/splstack.inc
new file mode 100644
index 0000000..70b1443
--- /dev/null
+++ b/ext/spl/internal/splstack.inc
@@ -0,0 +1,48 @@
+<?php
+
+/** @file splstack.inc
+ * @ingroup SPL
+ * @brief class SplStack
+ * @author Etienne Kneuss
+ * @date 2008 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup SPL
+ * @brief Implementation of a stack through a DoublyLinkedList. As SplStack
+ * extends SplDoublyLinkedList, shift() and unshift() are still available even
+ * though they don't make much sense for a stack.
+ * @since PHP 5.3
+ *
+ * The SplStack class provides the main functionalities of a
+ * stack implemented using a doubly linked list (DLL).
+ */
+class SplStack extends SplDoublyLinkedList
+{
+ protected $_it_mode = parent::IT_MODE_LIFO;
+
+ /** Changes the iteration mode. There are two orthogonal sets of modes that
+ * can be set:
+ *
+ * - The behavior of the iterator (either one or the other)
+ * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator)
+ * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator)
+ *
+ * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP
+ *
+ * @note The iteration's direction is not modifiable for stack instances
+ * @param $mode New mode of iteration
+ * @throw RuntimeException If the new mode affects the iteration's direction.
+ */
+ public function setIteratorMode($mode)
+ {
+ if ($mode & parent::IT_MODE_LIFO !== parent::IT_MODE_LIFO) {
+ throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen");
+ }
+
+ $this->_it_mode = $mode;
+ }
+}
+
+?>
diff --git a/ext/spl/package.xml b/ext/spl/package.xml
new file mode 100755
index 0000000..372aaec
--- /dev/null
+++ b/ext/spl/package.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package>
+ <name>SPL</name>
+ <summary>Standard PHP Library</summary>
+ <maintainers>
+ <maintainer>
+ <user>helly</user>
+ <name>Marcus Boerger</name>
+ <email>helly@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+ <description>
+SPL is a collection of interfaces and classes that are meant to solve
+standard problems.
+ </description>
+ <license>PHP</license>
+ <release>
+ <state>stable</state>
+ <version>0.1-dev</version>
+ <date>TBA</date>
+ <filelist>
+ <file role="src" name="config.m4"/>
+ <file role="src" name="php_spl.c"/>
+ <file role="src" name="php_spl.h"/>
+ <file role="src" name="spl_array.c"/>
+ <file role="src" name="spl_array.h"/>
+ <file role="src" name="spl_directory.c"/>
+ <file role="src" name="spl_directory.h"/>
+ <file role="src" name="spl_engine.c"/>
+ <file role="src" name="spl_engine.h"/>
+ <file role="src" name="spl_functions.c"/>
+ <file role="src" name="spl_functions.h"/>
+ <file role="src" name="spl_iterators.c"/>
+ <file role="src" name="spl_iterators.h"/>
+ <file role="doc" name="CREDITS"/>
+ <file role="doc" name="README"/>
+ <file role="doc" name="TODO"/>
+ <file role="doc" name="spl.php"/>
+ <file role="test" name="tests/array_iterator.phpt"/>
+ <file role="test" name="tests/array_object.phpt"/>
+ <dir name="examples">
+ <file role="doc" name="autoload.inc"/>
+ <file role="doc" name="cachingiterator.inc"/>
+ <file role="doc" name="cachingrecursiveiterator.inc"/>
+ <file role="doc" name="dba_array.php"/>
+ <file role="doc" name="dba_dump.php"/>
+ <file role="doc" name="dba_reader.inc"/>
+ <file role="doc" name="directoryfilterdots.inc"/>
+ <file role="doc" name="directorygraphiterator.inc"/>
+ <file role="doc" name="directorytree.inc"/>
+ <file role="doc" name="directorytree.php"/>
+ <file role="doc" name="directorytreeiterator.inc"/>
+ <file role="doc" name="findfile.php"/>
+ <file role="doc" name="filteriterator.inc"/>
+ <file role="doc" name="ini_groups.php"/>
+ <file role="doc" name="key_filter.inc"/>
+ <file role="doc" name="limititerator.inc"/>
+ <file role="doc" name="parentiterator.inc"/>
+ <file role="doc" name="recursiveiterator.inc"/>
+ <file role="doc" name="recursiveiteratoriterator.inc"/>
+ <file role="doc" name="searchiterator.inc"/>
+ <file role="doc" name="seekableiterator.inc"/>
+ <file role="doc" name="tree.php"/>
+ </dir>
+ </filelist>
+ <deps>
+ <dep type="php" rel="ge" version="5"/>
+ </deps>
+ </release>
+</package>
+<!--
+vim:et:ts=1:sw=1
+-->
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
new file mode 100644
index 0000000..35f4e50
--- /dev/null
+++ b/ext/spl/php_spl.c
@@ -0,0 +1,1001 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "php_main.h"
+#include "ext/standard/info.h"
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_array.h"
+#include "spl_directory.h"
+#include "spl_iterators.h"
+#include "spl_exceptions.h"
+#include "spl_observer.h"
+#include "spl_dllist.h"
+#include "spl_fixedarray.h"
+#include "spl_heap.h"
+#include "zend_exceptions.h"
+#include "zend_interfaces.h"
+#include "ext/standard/php_rand.h"
+#include "ext/standard/php_lcg.h"
+#include "main/snprintf.h"
+
+#ifdef COMPILE_DL_SPL
+ZEND_GET_MODULE(spl)
+#endif
+
+ZEND_DECLARE_MODULE_GLOBALS(spl)
+
+#define SPL_DEFAULT_FILE_EXTENSIONS ".inc,.php"
+
+/* {{{ PHP_GINIT_FUNCTION
+ */
+static PHP_GINIT_FUNCTION(spl)
+{
+ spl_globals->autoload_extensions = NULL;
+ spl_globals->autoload_extensions_len = 0;
+ spl_globals->autoload_functions = NULL;
+ spl_globals->autoload_running = 0;
+}
+/* }}} */
+
+static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool autoload TSRMLS_DC)
+{
+ zend_class_entry **ce;
+ int found;
+
+ if (!autoload) {
+ char *lc_name;
+ ALLOCA_FLAG(use_heap)
+
+ lc_name = do_alloca(len + 1, use_heap);
+ zend_str_tolower_copy(lc_name, name, len);
+
+ found = zend_hash_find(EG(class_table), lc_name, len +1, (void **) &ce);
+ free_alloca(lc_name, use_heap);
+ } else {
+ found = zend_lookup_class(name, len, &ce TSRMLS_CC);
+ }
+ if (found != SUCCESS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist%s", name, autoload ? " and could not be loaded" : "");
+ return NULL;
+ }
+
+ return *ce;
+}
+
+/* {{{ proto array class_parents(object instance [, boolean autoload = true])
+ Return an array containing the names of all parent classes */
+PHP_FUNCTION(class_parents)
+{
+ zval *obj;
+ zend_class_entry *parent_class, *ce;
+ zend_bool autoload = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected");
+ RETURN_FALSE;
+ }
+
+ if (Z_TYPE_P(obj) == IS_STRING) {
+ if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) {
+ RETURN_FALSE;
+ }
+ } else {
+ ce = Z_OBJCE_P(obj);
+ }
+
+ array_init(return_value);
+ parent_class = ce->parent;
+ while (parent_class) {
+ spl_add_class_name(return_value, parent_class, 0, 0 TSRMLS_CC);
+ parent_class = parent_class->parent;
+ }
+}
+/* }}} */
+
+/* {{{ proto array class_implements(mixed what [, bool autoload ])
+ Return all classes and interfaces implemented by SPL */
+PHP_FUNCTION(class_implements)
+{
+ zval *obj;
+ zend_bool autoload = 1;
+ zend_class_entry *ce;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) {
+ RETURN_FALSE;
+ }
+ if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected");
+ RETURN_FALSE;
+ }
+
+ if (Z_TYPE_P(obj) == IS_STRING) {
+ if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) {
+ RETURN_FALSE;
+ }
+ } else {
+ ce = Z_OBJCE_P(obj);
+ }
+
+ array_init(return_value);
+ spl_add_interfaces(return_value, ce, 1, ZEND_ACC_INTERFACE TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto array class_uses(mixed what [, bool autoload ])
+ Return all traits used by a class. */
+PHP_FUNCTION(class_uses)
+{
+ zval *obj;
+ zend_bool autoload = 1;
+ zend_class_entry *ce;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) {
+ RETURN_FALSE;
+ }
+ if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected");
+ RETURN_FALSE;
+ }
+
+ if (Z_TYPE_P(obj) == IS_STRING) {
+ if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) {
+ RETURN_FALSE;
+ }
+ } else {
+ ce = Z_OBJCE_P(obj);
+ }
+
+ array_init(return_value);
+ spl_add_traits(return_value, ce, 1, ZEND_ACC_TRAIT TSRMLS_CC);
+}
+/* }}} */
+
+#define SPL_ADD_CLASS(class_name, z_list, sub, allow, ce_flags) \
+ spl_add_classes(spl_ce_ ## class_name, z_list, sub, allow, ce_flags TSRMLS_CC)
+
+#define SPL_LIST_CLASSES(z_list, sub, allow, ce_flags) \
+ SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(CallbackFilterIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(Countable, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(DirectoryIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(DomainException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(EmptyIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(FilesystemIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(FilterIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(GlobIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(InfiniteIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(InvalidArgumentException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(IteratorIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(MultipleIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(OverflowException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RangeException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveArrayIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveCachingIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveCallbackFilterIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveFilterIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveTreeIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RegexIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \
+
+/* {{{ proto array spl_classes()
+ Return an array containing the names of all clsses and interfaces defined in SPL */
+PHP_FUNCTION(spl_classes)
+{
+ array_init(return_value);
+
+ SPL_LIST_CLASSES(return_value, 0, 0, 0)
+}
+/* }}} */
+
+static int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */
+{
+ char *class_file;
+ int class_file_len;
+ int dummy = 1;
+ zend_file_handle file_handle;
+ zend_op_array *new_op_array;
+ zval *result = NULL;
+ int ret;
+
+ class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);
+
+#if DEFAULT_SLASH != '\\'
+ {
+ char *ptr = class_file;
+ char *end = ptr + class_file_len;
+
+ while ((ptr = memchr(ptr, '\\', (end - ptr))) != NULL) {
+ *ptr = DEFAULT_SLASH;
+ }
+ }
+#endif
+
+ ret = php_stream_open_for_zend_ex(class_file, &file_handle, USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+
+ if (ret == SUCCESS) {
+ if (!file_handle.opened_path) {
+ file_handle.opened_path = estrndup(class_file, class_file_len);
+ }
+ if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
+ new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
+ zend_destroy_file_handle(&file_handle TSRMLS_CC);
+ } else {
+ new_op_array = NULL;
+ zend_file_handle_dtor(&file_handle TSRMLS_CC);
+ }
+ if (new_op_array) {
+ EG(return_value_ptr_ptr) = &result;
+ EG(active_op_array) = new_op_array;
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+
+ zend_execute(new_op_array TSRMLS_CC);
+
+ destroy_op_array(new_op_array TSRMLS_CC);
+ efree(new_op_array);
+ if (!EG(exception)) {
+ if (EG(return_value_ptr_ptr)) {
+ zval_ptr_dtor(EG(return_value_ptr_ptr));
+ }
+ }
+
+ efree(class_file);
+ return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1);
+ }
+ }
+ efree(class_file);
+ return 0;
+} /* }}} */
+
+/* {{{ proto void spl_autoload(string class_name [, string file_extensions])
+ Default implementation for __autoload() */
+PHP_FUNCTION(spl_autoload)
+{
+ char *class_name, *lc_name, *file_exts = SPL_G(autoload_extensions);
+ int class_name_len, file_exts_len = SPL_G(autoload_extensions_len), found = 0;
+ char *copy, *pos1, *pos2;
+ zval **original_return_value = EG(return_value_ptr_ptr);
+ zend_op **original_opline_ptr = EG(opline_ptr);
+ zend_op_array *original_active_op_array = EG(active_op_array);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &class_name, &class_name_len, &file_exts, &file_exts_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (file_exts == NULL) { /* autoload_extensions is not intialzed, set to defaults */
+ copy = pos1 = estrndup(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS)-1);
+ } else {
+ copy = pos1 = estrndup(file_exts, file_exts_len);
+ }
+ lc_name = zend_str_tolower_dup(class_name, class_name_len);
+ while(pos1 && *pos1 && !EG(exception)) {
+ EG(return_value_ptr_ptr) = original_return_value;
+ EG(opline_ptr) = original_opline_ptr;
+ EG(active_op_array) = original_active_op_array;
+ pos2 = strchr(pos1, ',');
+ if (pos2) *pos2 = '\0';
+ if (spl_autoload(class_name, lc_name, class_name_len, pos1 TSRMLS_CC)) {
+ found = 1;
+ break; /* loaded */
+ }
+ pos1 = pos2 ? pos2 + 1 : NULL;
+ }
+ efree(lc_name);
+ if (copy) {
+ efree(copy);
+ }
+
+ EG(return_value_ptr_ptr) = original_return_value;
+ EG(opline_ptr) = original_opline_ptr;
+ EG(active_op_array) = original_active_op_array;
+
+ if (!found && !SPL_G(autoload_running)) {
+ /* For internal errors, we generate E_ERROR, for direct calls an exception is thrown.
+ * The "scope" is determined by an opcode, if it is ZEND_FETCH_CLASS we know function was called indirectly by
+ * the Zend engine.
+ */
+ if (active_opline->opcode != ZEND_FETCH_CLASS) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Class %s could not be loaded", class_name);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be loaded", class_name);
+ }
+ }
+} /* }}} */
+
+/* {{{ proto string spl_autoload_extensions([string file_extensions])
+ Register and return default file extensions for spl_autoload */
+PHP_FUNCTION(spl_autoload_extensions)
+{
+ char *file_exts = NULL;
+ int file_exts_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file_exts, &file_exts_len) == FAILURE) {
+ return;
+ }
+ if (file_exts) {
+ if (SPL_G(autoload_extensions)) {
+ efree(SPL_G(autoload_extensions));
+ }
+ SPL_G(autoload_extensions) = estrndup(file_exts, file_exts_len);
+ SPL_G(autoload_extensions_len) = file_exts_len;
+ }
+
+ if (SPL_G(autoload_extensions) == NULL) {
+ RETURN_STRINGL(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS) - 1, 1);
+ } else {
+ RETURN_STRINGL(SPL_G(autoload_extensions), SPL_G(autoload_extensions_len), 1);
+ }
+} /* }}} */
+
+typedef struct {
+ zend_function *func_ptr;
+ zval *obj;
+ zval *closure;
+ zend_class_entry *ce;
+} autoload_func_info;
+
+static void autoload_func_info_dtor(autoload_func_info *alfi)
+{
+ if (alfi->obj) {
+ zval_ptr_dtor(&alfi->obj);
+ }
+ if (alfi->closure) {
+ zval_ptr_dtor(&alfi->closure);
+ }
+}
+
+/* {{{ proto void spl_autoload_call(string class_name)
+ Try all registerd autoload function to load the requested class */
+PHP_FUNCTION(spl_autoload_call)
+{
+ zval *class_name, *retval = NULL;
+ int class_name_len;
+ char *func_name, *lc_name;
+ uint func_name_len;
+ ulong dummy;
+ HashPosition function_pos;
+ autoload_func_info *alfi;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) {
+ return;
+ }
+
+ if (SPL_G(autoload_functions)) {
+ int l_autoload_running = SPL_G(autoload_running);
+ SPL_G(autoload_running) = 1;
+ class_name_len = Z_STRLEN_P(class_name);
+ lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len);
+ zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
+ while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) {
+ zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos);
+ zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
+ zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC);
+ zend_exception_save(TSRMLS_C);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ retval = NULL;
+ }
+ if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) {
+ break;
+ }
+ zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
+ }
+ zend_exception_restore(TSRMLS_C);
+ efree(lc_name);
+ SPL_G(autoload_running) = l_autoload_running;
+ } else {
+ /* do not use or overwrite &EG(autoload_func) here */
+ zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name);
+ }
+} /* }}} */
+
+#define HT_MOVE_TAIL_TO_HEAD(ht) \
+ (ht)->pListTail->pListNext = (ht)->pListHead; \
+ (ht)->pListHead = (ht)->pListTail; \
+ (ht)->pListTail = (ht)->pListHead->pListLast; \
+ (ht)->pListHead->pListNext->pListLast = (ht)->pListHead;\
+ (ht)->pListTail->pListNext = NULL; \
+ (ht)->pListHead->pListLast = NULL;
+
+/* {{{ proto bool spl_autoload_register([mixed autoload_function = "spl_autoload" [, throw = true [, prepend]]])
+ Register given function as __autoload() implementation */
+PHP_FUNCTION(spl_autoload_register)
+{
+ char *func_name, *error = NULL;
+ int func_name_len;
+ char *lc_name = NULL;
+ zval *zcallable = NULL;
+ zend_bool do_throw = 1;
+ zend_bool prepend = 0;
+ zend_function *spl_func_ptr;
+ autoload_func_info alfi;
+ zval *obj_ptr;
+ zend_fcall_info_cache fcc;
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|zbb", &zcallable, &do_throw, &prepend) == FAILURE) {
+ return;
+ }
+
+ if (ZEND_NUM_ARGS()) {
+ if (Z_TYPE_P(zcallable) == IS_STRING) {
+ if (Z_STRLEN_P(zcallable) == sizeof("spl_autoload_call") - 1) {
+ if (!zend_binary_strcasecmp(Z_STRVAL_P(zcallable), sizeof("spl_autoload_call"), "spl_autoload_call", sizeof("spl_autoload_call"))) {
+ if (do_throw) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function spl_autoload_call() cannot be registered");
+ }
+ RETURN_FALSE;
+ }
+ }
+ }
+
+ if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) {
+ alfi.ce = fcc.calling_scope;
+ alfi.func_ptr = fcc.function_handler;
+ obj_ptr = fcc.object_ptr;
+ if (Z_TYPE_P(zcallable) == IS_ARRAY) {
+ if (!obj_ptr && alfi.func_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ if (do_throw) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error);
+ }
+ if (error) {
+ efree(error);
+ }
+ efree(func_name);
+ RETURN_FALSE;
+ }
+ else if (do_throw) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", alfi.func_ptr ? "a callable" : "an existing", !obj_ptr ? "static " : "", error);
+ }
+ if (error) {
+ efree(error);
+ }
+ efree(func_name);
+ RETURN_FALSE;
+ } else if (Z_TYPE_P(zcallable) == IS_STRING) {
+ if (do_throw) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", func_name, alfi.func_ptr ? "callable" : "found", error);
+ }
+ if (error) {
+ efree(error);
+ }
+ efree(func_name);
+ RETURN_FALSE;
+ } else {
+ if (do_throw) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error);
+ }
+ if (error) {
+ efree(error);
+ }
+ efree(func_name);
+ RETURN_FALSE;
+ }
+ }
+ alfi.closure = NULL;
+ alfi.ce = fcc.calling_scope;
+ alfi.func_ptr = fcc.function_handler;
+ obj_ptr = fcc.object_ptr;
+ if (error) {
+ efree(error);
+ }
+
+ lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
+ zend_str_tolower_copy(lc_name, func_name, func_name_len);
+ efree(func_name);
+
+ if (Z_TYPE_P(zcallable) == IS_OBJECT) {
+ alfi.closure = zcallable;
+ Z_ADDREF_P(zcallable);
+
+ lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
+ memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable),
+ sizeof(zend_object_handle));
+ func_name_len += sizeof(zend_object_handle);
+ lc_name[func_name_len] = '\0';
+ }
+
+ if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), (char*)lc_name, func_name_len+1)) {
+ if (alfi.closure) {
+ Z_DELREF_P(zcallable);
+ }
+ goto skip;
+ }
+
+ if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ /* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */
+ lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
+ memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
+ func_name_len += sizeof(zend_object_handle);
+ lc_name[func_name_len] = '\0';
+ alfi.obj = obj_ptr;
+ Z_ADDREF_P(alfi.obj);
+ } else {
+ alfi.obj = NULL;
+ }
+
+ if (!SPL_G(autoload_functions)) {
+ ALLOC_HASHTABLE(SPL_G(autoload_functions));
+ zend_hash_init(SPL_G(autoload_functions), 1, NULL, (dtor_func_t) autoload_func_info_dtor, 0);
+ }
+
+ zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
+
+ if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */
+ autoload_func_info spl_alfi;
+
+ spl_alfi.func_ptr = spl_func_ptr;
+ spl_alfi.obj = NULL;
+ spl_alfi.ce = NULL;
+ spl_alfi.closure = NULL;
+ zend_hash_add(SPL_G(autoload_functions), "spl_autoload", sizeof("spl_autoload"), &spl_alfi, sizeof(autoload_func_info), NULL);
+ if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
+ /* Move the newly created element to the head of the hashtable */
+ HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions));
+ }
+ }
+
+ if (zend_hash_add(SPL_G(autoload_functions), lc_name, func_name_len+1, &alfi.func_ptr, sizeof(autoload_func_info), NULL) == FAILURE) {
+ if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ Z_DELREF_P(alfi.obj);
+ }
+ if (alfi.closure) {
+ Z_DELREF_P(alfi.closure);
+ }
+ }
+ if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
+ /* Move the newly created element to the head of the hashtable */
+ HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions));
+ }
+skip:
+ efree(lc_name);
+ }
+
+ if (SPL_G(autoload_functions)) {
+ zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &EG(autoload_func));
+ } else {
+ zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &EG(autoload_func));
+ }
+ RETURN_TRUE;
+} /* }}} */
+
+/* {{{ proto bool spl_autoload_unregister(mixed autoload_function)
+ Unregister given function as __autoload() implementation */
+PHP_FUNCTION(spl_autoload_unregister)
+{
+ char *func_name, *error = NULL;
+ int func_name_len;
+ char *lc_name = NULL;
+ zval *zcallable;
+ int success = FAILURE;
+ zend_function *spl_func_ptr;
+ zval *obj_ptr;
+ zend_fcall_info_cache fcc;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcallable) == FAILURE) {
+ return;
+ }
+
+ if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_CHECK_SYNTAX_ONLY, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Unable to unregister invalid function (%s)", error);
+ if (error) {
+ efree(error);
+ }
+ if (func_name) {
+ efree(func_name);
+ }
+ RETURN_FALSE;
+ }
+ obj_ptr = fcc.object_ptr;
+ if (error) {
+ efree(error);
+ }
+
+ lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
+ zend_str_tolower_copy(lc_name, func_name, func_name_len);
+ efree(func_name);
+
+ if (Z_TYPE_P(zcallable) == IS_OBJECT) {
+ lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
+ memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable),
+ sizeof(zend_object_handle));
+ func_name_len += sizeof(zend_object_handle);
+ lc_name[func_name_len] = '\0';
+ }
+
+ if (SPL_G(autoload_functions)) {
+ if (func_name_len == sizeof("spl_autoload_call")-1 && !strcmp(lc_name, "spl_autoload_call")) {
+ /* remove all */
+ zend_hash_destroy(SPL_G(autoload_functions));
+ FREE_HASHTABLE(SPL_G(autoload_functions));
+ SPL_G(autoload_functions) = NULL;
+ EG(autoload_func) = NULL;
+ success = SUCCESS;
+ } else {
+ /* remove specific */
+ success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1);
+ if (success != SUCCESS && obj_ptr) {
+ lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
+ memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
+ func_name_len += sizeof(zend_object_handle);
+ lc_name[func_name_len] = '\0';
+ success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1);
+ }
+ }
+ } else if (func_name_len == sizeof("spl_autoload")-1 && !strcmp(lc_name, "spl_autoload")) {
+ /* register single spl_autoload() */
+ zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
+
+ if (EG(autoload_func) == spl_func_ptr) {
+ success = SUCCESS;
+ EG(autoload_func) = NULL;
+ }
+ }
+
+ efree(lc_name);
+ RETURN_BOOL(success == SUCCESS);
+} /* }}} */
+
+/* {{{ proto false|array spl_autoload_functions()
+ Return all registered __autoload() functionns */
+PHP_FUNCTION(spl_autoload_functions)
+{
+ zend_function *fptr;
+ HashPosition function_pos;
+ autoload_func_info *alfi;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!EG(autoload_func)) {
+ if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) {
+ array_init(return_value);
+ add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1);
+ return;
+ }
+ RETURN_FALSE;
+ }
+
+ zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &fptr);
+
+ if (EG(autoload_func) == fptr) {
+ array_init(return_value);
+ zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
+ while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) {
+ zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
+ if (alfi->closure) {
+ Z_ADDREF_P(alfi->closure);
+ add_next_index_zval(return_value, alfi->closure);
+ } else if (alfi->func_ptr->common.scope) {
+ zval *tmp;
+ MAKE_STD_ZVAL(tmp);
+ array_init(tmp);
+
+ if (alfi->obj) {
+ Z_ADDREF_P(alfi->obj);
+ add_next_index_zval(tmp, alfi->obj);
+ } else {
+ add_next_index_string(tmp, alfi->ce->name, 1);
+ }
+ add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1);
+ add_next_index_zval(return_value, tmp);
+ } else
+ add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1);
+
+ zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
+ }
+ return;
+ }
+
+ array_init(return_value);
+ add_next_index_string(return_value, EG(autoload_func)->common.function_name, 1);
+} /* }}} */
+
+/* {{{ proto string spl_object_hash(object obj)
+ Return hash id for given object */
+PHP_FUNCTION(spl_object_hash)
+{
+ zval *obj;
+ char* hash;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+
+ hash = emalloc(33);
+ php_spl_object_hash(obj, hash TSRMLS_CC);
+
+ RETVAL_STRING(hash, 0);
+}
+/* }}} */
+
+PHPAPI void php_spl_object_hash(zval *obj, char *result TSRMLS_DC) /* {{{*/
+{
+ intptr_t hash_handle, hash_handlers;
+ char *hex;
+
+ if (!SPL_G(hash_mask_init)) {
+ if (!BG(mt_rand_is_seeded)) {
+ php_mt_srand(GENERATE_SEED() TSRMLS_CC);
+ }
+
+ SPL_G(hash_mask_handle) = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1);
+ SPL_G(hash_mask_handlers) = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1);
+ SPL_G(hash_mask_init) = 1;
+ }
+
+ hash_handle = SPL_G(hash_mask_handle)^(intptr_t)Z_OBJ_HANDLE_P(obj);
+ hash_handlers = SPL_G(hash_mask_handlers)^(intptr_t)Z_OBJ_HT_P(obj);
+
+ spprintf(&hex, 32, "%016x%016x", hash_handle, hash_handlers);
+
+ strlcpy(result, hex, 33);
+ efree(hex);
+}
+/* }}} */
+
+int spl_build_class_list_string(zval **entry, char **list TSRMLS_DC) /* {{{ */
+{
+ char *res;
+
+ spprintf(&res, 0, "%s, %s", *list, Z_STRVAL_PP(entry));
+ efree(*list);
+ *list = res;
+ return ZEND_HASH_APPLY_KEEP;
+} /* }}} */
+
+/* {{{ PHP_MINFO(spl)
+ */
+PHP_MINFO_FUNCTION(spl)
+{
+ zval list;
+ char *strg;
+
+ php_info_print_table_start();
+ php_info_print_table_header(2, "SPL support", "enabled");
+
+ INIT_PZVAL(&list);
+ array_init(&list);
+ SPL_LIST_CLASSES(&list, 0, 1, ZEND_ACC_INTERFACE)
+ strg = estrdup("");
+ zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC);
+ zval_dtor(&list);
+ php_info_print_table_row(2, "Interfaces", strg + 2);
+ efree(strg);
+
+ INIT_PZVAL(&list);
+ array_init(&list);
+ SPL_LIST_CLASSES(&list, 0, -1, ZEND_ACC_INTERFACE)
+ strg = estrdup("");
+ zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC);
+ zval_dtor(&list);
+ php_info_print_table_row(2, "Classes", strg + 2);
+ efree(strg);
+
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_to_array, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ ZEND_ARG_INFO(0, use_keys)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_iterator, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_apply, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ ZEND_ARG_INFO(0, function)
+ ZEND_ARG_ARRAY_INFO(0, args, 1)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_parents, 0, 0, 1)
+ ZEND_ARG_INFO(0, instance)
+ ZEND_ARG_INFO(0, autoload)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_implements, 0, 0, 1)
+ ZEND_ARG_INFO(0, what)
+ ZEND_ARG_INFO(0, autoload)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_uses, 0, 0, 1)
+ ZEND_ARG_INFO(0, what)
+ ZEND_ARG_INFO(0, autoload)
+ZEND_END_ARG_INFO()
+
+
+ZEND_BEGIN_ARG_INFO(arginfo_spl_classes, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_spl_autoload_functions, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload, 0, 0, 1)
+ ZEND_ARG_INFO(0, class_name)
+ ZEND_ARG_INFO(0, file_extensions)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_extensions, 0, 0, 0)
+ ZEND_ARG_INFO(0, file_extensions)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_call, 0, 0, 1)
+ ZEND_ARG_INFO(0, class_name)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_register, 0, 0, 0)
+ ZEND_ARG_INFO(0, autoload_function)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_unregister, 0, 0, 1)
+ ZEND_ARG_INFO(0, autoload_function)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_object_hash, 0, 0, 1)
+ ZEND_ARG_INFO(0, obj)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ spl_functions
+ */
+const zend_function_entry spl_functions[] = {
+ PHP_FE(spl_classes, arginfo_spl_classes)
+ PHP_FE(spl_autoload, arginfo_spl_autoload)
+ PHP_FE(spl_autoload_extensions, arginfo_spl_autoload_extensions)
+ PHP_FE(spl_autoload_register, arginfo_spl_autoload_register)
+ PHP_FE(spl_autoload_unregister, arginfo_spl_autoload_unregister)
+ PHP_FE(spl_autoload_functions, arginfo_spl_autoload_functions)
+ PHP_FE(spl_autoload_call, arginfo_spl_autoload_call)
+ PHP_FE(class_parents, arginfo_class_parents)
+ PHP_FE(class_implements, arginfo_class_implements)
+ PHP_FE(class_uses, arginfo_class_uses)
+ PHP_FE(spl_object_hash, arginfo_spl_object_hash)
+#ifdef SPL_ITERATORS_H
+ PHP_FE(iterator_to_array, arginfo_iterator_to_array)
+ PHP_FE(iterator_count, arginfo_iterator)
+ PHP_FE(iterator_apply, arginfo_iterator_apply)
+#endif /* SPL_ITERATORS_H */
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION(spl)
+ */
+PHP_MINIT_FUNCTION(spl)
+{
+ PHP_MINIT(spl_exceptions)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_dllist)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_fixedarray)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
+
+ return SUCCESS;
+}
+/* }}} */
+
+PHP_RINIT_FUNCTION(spl) /* {{{ */
+{
+ SPL_G(autoload_extensions) = NULL;
+ SPL_G(autoload_extensions_len) = 0;
+ SPL_G(autoload_functions) = NULL;
+ SPL_G(hash_mask_init) = 0;
+ return SUCCESS;
+} /* }}} */
+
+PHP_RSHUTDOWN_FUNCTION(spl) /* {{{ */
+{
+ if (SPL_G(autoload_extensions)) {
+ efree(SPL_G(autoload_extensions));
+ SPL_G(autoload_extensions) = NULL;
+ SPL_G(autoload_extensions_len) = 0;
+ }
+ if (SPL_G(autoload_functions)) {
+ zend_hash_destroy(SPL_G(autoload_functions));
+ FREE_HASHTABLE(SPL_G(autoload_functions));
+ SPL_G(autoload_functions) = NULL;
+ }
+ if (SPL_G(hash_mask_init)) {
+ SPL_G(hash_mask_init) = 0;
+ }
+ return SUCCESS;
+} /* }}} */
+
+/* {{{ spl_module_entry
+ */
+zend_module_entry spl_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "SPL",
+ spl_functions,
+ PHP_MINIT(spl),
+ NULL,
+ PHP_RINIT(spl),
+ PHP_RSHUTDOWN(spl),
+ PHP_MINFO(spl),
+ "0.2",
+ PHP_MODULE_GLOBALS(spl),
+ PHP_GINIT(spl),
+ NULL,
+ NULL,
+ STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h
new file mode 100644
index 0000000..4794f12
--- /dev/null
+++ b/ext/spl/php_spl.h
@@ -0,0 +1,99 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef PHP_SPL_H
+#define PHP_SPL_H
+
+#include "php.h"
+#if defined(PHP_WIN32)
+# include "win32/php_stdint.h"
+#elif defined(HAVE_STDINT_H)
+# include <stdint.h>
+#endif
+#include <stdarg.h>
+
+#if 0
+#define SPL_DEBUG(x) x
+#else
+#define SPL_DEBUG(x)
+#endif
+
+extern zend_module_entry spl_module_entry;
+#define phpext_spl_ptr &spl_module_entry
+
+#ifdef PHP_WIN32
+# ifdef SPL_EXPORTS
+# define SPL_API __declspec(dllexport)
+# elif defined(COMPILE_DL_SPL)
+# define SPL_API __declspec(dllimport)
+# else
+# define SPL_API /* nothing */
+# endif
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define SPL_API __attribute__ ((visibility("default")))
+#else
+# define SPL_API
+#endif
+
+#if defined(PHP_WIN32) && !defined(COMPILE_DL_SPL)
+#undef phpext_spl
+#define phpext_spl NULL
+#endif
+
+PHP_MINIT_FUNCTION(spl);
+PHP_MSHUTDOWN_FUNCTION(spl);
+PHP_RINIT_FUNCTION(spl);
+PHP_RSHUTDOWN_FUNCTION(spl);
+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;
+ZEND_END_MODULE_GLOBALS(spl)
+
+#ifdef ZTS
+# define SPL_G(v) TSRMG(spl_globals_id, zend_spl_globals *, v)
+extern int spl_globals_id;
+#else
+# define SPL_G(v) (spl_globals.v)
+extern zend_spl_globals spl_globals;
+#endif
+
+PHP_FUNCTION(spl_classes);
+PHP_FUNCTION(class_parents);
+PHP_FUNCTION(class_implements);
+PHP_FUNCTION(class_uses);
+
+PHPAPI void php_spl_object_hash(zval *obj, char* md5str TSRMLS_DC);
+
+#endif /* PHP_SPL_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl.php b/ext/spl/spl.php
new file mode 100755
index 0000000..fdffda3
--- /dev/null
+++ b/ext/spl/spl.php
@@ -0,0 +1,1163 @@
+<?php
+
+/** @file spl.php
+ * @ingroup SPL
+ * @brief Documentation of internal classes and interfaces
+ *
+ * SPL - Standard PHP Library
+ *
+ * (c) Marcus Boerger, 2003 - 2008
+ */
+
+/** @mainpage SPL - Standard PHP Library
+ *
+ * SPL - Standard PHP Library
+ *
+ * SPL is a collection of interfaces and classes that are meant to solve
+ * standard problems and implements some efficient data access interfaces
+ * and classes. You'll find the classes documented using php code in the
+ * file spl.php or in corresponding .inc files in subdirectories examples
+ * and internal. Based on the internal implementations or the files in the
+ * examples subdirectory there are also some .php files to experiment with.
+ *
+ * The .inc files are not included automatically because they are sooner or
+ * later integrated into the extension. That means that you either need to
+ * put the code of examples/autoload.inc into your autoprepend file or that
+ * you have to point your ini setting auto_prepend_file to that file.
+ *
+ * Below is a list of interfaces/classes already availabel natively through
+ * the SPL extension grouped by category.
+ *
+ * 1) Iterators
+ *
+ * SPL offers some advanced iterator algorithms:
+ *
+ * - interface RecursiveIterator extends Iterator
+ * - interface OuterIterator extends Iterator
+ * - class RecursiveIteratorIterator implements OuterIterator
+ * - class RecursiveTreeIterator extends RecursiveIteratorIterator
+ * - abstract class FilterIterator implements OuterIterator
+ * - class ParentIterator extends FilterIterator implements RecursiveIterator
+ * - interface SeekableIterator extends Iterator
+ * - class LimitIterator implements OuterIterator
+ * - class CachingIterator implements OuterIterator
+ * - class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator
+ * - class IteratorIterator implements OuterIterator
+ * - class NoRewindIterator implements OuterIterator
+ * - class EmptyIterator implements Iterator
+ * - class InfiniteIterator extends IteratorIterator
+ * - class AppendIterator implements OuterIterator
+ * - class RegexIterator extends FilterIterator
+ * - class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator
+ * - class MultipleIterator extends Iterator
+ *
+ * 2) Directories and Files
+ *
+ * SPL offers two advanced directory and file handling classes:
+ *
+ * - class SplFileInfo
+ * - class DirectoryIterator extends SplFileInfo implements Iterator
+ * - class FilesystemIterator extends DirectoryIterator
+ * - class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator
+ * - class GlobIterator extends FilesystemIterator implements Countable
+ * - class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator
+ * - class SplTempFileObject extends SplFileObject
+ *
+ * 3) XML
+ *
+ * SPL offers an advanced XML handling class:
+ *
+ * - class SimpleXMLIterator extends simplexml_element implements RecursiveIterator
+ *
+ * 4) Array Overloading
+ *
+ * SPL offers advanced Array overloading:
+ *
+ * - class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
+ * - class ArrayIterator implements Iterator, ArrayAccess, Countable, SeekableIterator
+ * - class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
+ * - class SplFixedArray implements Iterator, ArrayAccess, Countable
+ *
+ * As the above suggest an ArrayObject creates an ArrayIterator when it comes to
+ * iteration (e.g. ArrayObject instance used inside foreach).
+ *
+ * 5) Counting
+ *
+ * - interface Countable allows to hook into the standard array function count().
+ *
+ * 6) Exception%s
+ *
+ * SPL provides a set of standard Exception classes each meant to indicate a
+ * certain problem type.
+ *
+ * - class LogicException extends Exception
+ * - class BadFunctionCallException extends LogicException
+ * - class BadMethodCallException extends BadFunctionCallException
+ * - class DomainException extends LogicException
+ * - class InvalidArgumentException extends LogicException
+ * - class LengthException extends LogicException
+ * - class OutOfRangeException extends LogicException
+ * - class RuntimeException extends Exception
+ * - class OutOfBoundsException extends RuntimeException
+ * - class OverflowException extends RuntimeException
+ * - class RangeException extends RuntimeException
+ * - class UnderflowException extends RuntimeException
+ *
+ * 7) Observer
+ *
+ * SPL suggests a standard way of implementing the observer pattern.
+ *
+ * - interface SplObserver
+ * - interface SplSubject
+ * - class SplObjectStorage
+ *
+ * 8) Datastructures
+ *
+ * SPL proposes a set of datastructures implemented internally.
+ *
+ * - class SplDoublyLinkedList
+ * - class SplStack extends SplDoublyLinkedList
+ * - class SplQueue extends SplDoublyLinkedList
+ *
+ * 9) @ref Examples
+ *
+ * The classes and interfaces in this group are contained as PHP code in the
+ * examples subdirectory of ext/SPL. Sooner or later they will be moved to
+ * c-code.
+ *
+ * 10) Some articles about SPL:
+ * - <a href="http://www.phpro.org/tutorials/Introduction-to-SPL.html">Introduction to Standard PHP Library (SPL)</a>
+ * - <a href="http://www.sitepoint.com/article/php5-standard-library/1">Introducing PHP 5's Standard Library</a>
+ * - <a href="http://www.ramikayyali.com/archives/2005/02/25/iterators">Iterators in PHP5</a>
+ * - <a href="http://www.phpriot.com/d/articles/php/oop/oop-with-spl-php-5-1/index.html">Advanced OOP with SPL in PHP 5</a>
+ * - <a href="http://www.devshed.com/c/a/PHP/The-Standard-PHP-Library-Part-1/">The Standard PHP Library, Part 1</a>
+ * - <a href="http://www.devshed.com/c/a/PHP/The-Standard-PHP-Library-Part-2/">The Standard PHP Library, Part 2</a>
+ * - <a href="http://www.professionelle-softwareentwicklung-mit-php5.de/erste_auflage/oop.iterators.spl.html">Die Standard PHP Library (SPL) [german]</a>
+ *
+ * 11) Talks on SPL:
+ * - SPL Update <a href="http://talks.somabo.de/200702_vancouver_spl_update.pps">[pps]</a>, <a href="http://talks.somabo.de/200702_vancouver_spl_update.pdf">[pdf]</a>
+ * - Happy SPLing <a href="http://talks.somabo.de/200509_toronto_happy_spling.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_happy_spling.pdf">[pdf]</a>
+ * - From engine overloading to SPL <a href="http://talks.somabo.de/200505_cancun_from_engine_overloading_to_spl.pps">[pps]</a>, <a href="http://talks.somabo.de/200505_cancun_from_engine_overloading_to_spl.pdf">[pdf]</a>
+ * - SPL for the masses <a href="http://talks.somabo.de/200504_php_quebec_spl_for_the_masses.pps">[pps]</a>, <a href="http://talks.somabo.de/200504_php_quebec_spl_for_the_masses.pdf">[pdf]</a>
+ *
+ * 12) Debug sessions:
+ * - Debug session 1 <a href="200407_oscon_introduction_to_iterators_debug.pps">[pps]</a>, <a href="200407_oscon_introduction_to_iterators_debug.pdf">[pdf]</a>
+ * - Debug session 2 <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_1.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_1.pdf">[pdf]</a>, <a href="http://taks.somabo.de/200411_php_conference_frankfrurt_iterator_debug_session.swf">[swf]</a>
+ * - Debug session 3 <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_2.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_2.pdf">[pdf]</a>
+ *
+ * You can download this documentation as a chm file
+ * <a href="http://php.net/~helly/php/ext/spl/spl.chm">here</a>.
+ *
+ * (c) Marcus Boerger, 2003 - 2007
+ */
+
+/** @defgroup ZendEngine Zend engine classes
+ *
+ * The classes and interfaces in this group are contained in the c-code of
+ * PHP's Zend engine.
+ */
+
+/** @defgroup SPL Internal classes
+ *
+ * The classes and interfaces in this group are contained in the c-code of
+ * ext/SPL.
+ */
+
+/** @defgroup Examples Example classes
+ *
+ * The classes and interfaces in this group are contained as PHP code in the
+ * examples subdirectory of ext/SPL. Sooner or later they will be moved to
+ * c-code.
+ */
+
+/** @ingroup SPL
+ * @brief Default implementation for __autoload()
+ * @since PHP 5.1
+ *
+ * @param class_name name of class to load
+ * @param file_extensions file extensions (use defaults if NULL)
+ */
+function spl_autoload(string $class_name, string $file_extensions = NULL) {/**/};
+
+/** @ingroup SPL
+ * @brief Manual invocation of all registerd autoload functions
+ * @since PHP 5.1
+ *
+ * @param class_name name of class to load
+ */
+function spl_autoload_call(string $class_name) {/**/};
+
+/** @ingroup SPL
+ * @brief Register and return default file extensions for spl_autoload
+ * @since PHP 5.1
+ *
+ * @param file_extensions optional comma separated list of extensions to use in
+ * default autoload function. If not given just return the current list.
+ * @return comma separated list of file extensions to use in default autoload
+ * function.
+ */
+function spl_autoload_extensions($file_extensions) {/**/};
+
+/** @ingroup SPL
+ * @brief Return all registered autoload functionns
+ * @since PHP 5.1
+ *
+ * @return array of all registered autoload functions or false
+ */
+function spl_autoload_functions() {/**/};
+
+/** @ingroup SPL
+ * @brief Register given function as autoload implementation
+ * @since PHP 5.1
+ *
+ * @param autoload_function name of function or array of object/class and
+ * function name to register as autoload function.
+ * @param throw whether to throw or issue an error on failure.
+ */
+function spl_autoload_register(string $autoload_function = "spl_autoload", $throw = true) {/**/};
+
+/** @ingroup SPL
+ * @brief Unregister given function as autoload implementation
+ * @since PHP 5.1
+ *
+ * @param autoload_function name of function or array of object/class and
+ * function name to unregister as autoload function.
+ */
+function spl_autoload_unregister(string $autoload_function = "spl_autoload") {/**/};
+
+/** @ingroup SPL
+ * @brief Return an array of classes and interfaces in SPL
+ *
+ * @return array containing the names of all clsses and interfaces defined in
+ * extension SPL
+ */
+function spl_classes() {/**/};
+
+/** @ingroup SPL
+ * @brief Count the elements in an iterator
+ * @since PHP 5.1
+ *
+ * @return number of elements in an iterator
+ */
+function iterator_count(Traversable $it) {/**/};
+
+/** @ingroup SPL
+ * @brief Copy iterator elements into an array
+ * @since PHP 5.1
+ *
+ * @param it iterator to copy
+ * @param use_keys whether touse the keys
+ * @return array with elements copied from the iterator
+ */
+function iterator_to_array(Traversable $it, $use_keys = true) {/**/};
+
+/** @ingroup ZendEngine
+ * @brief Basic Exception class.
+ * @since PHP 5.0
+ */
+class Exception
+{
+ /** The exception message */
+ protected $message;
+
+ /** The string represenations as generated during construction */
+ private $string;
+
+ /** The code passed to the constructor */
+ protected $code;
+
+ /** The file name where the exception was instantiated */
+ protected $file;
+
+ /** The line number where the exception was instantiated */
+ protected $line;
+
+ /** The stack trace */
+ private $trace;
+
+ /** Prevent clone
+ */
+ final private function __clone() {}
+
+ /** Construct an exception
+ *
+ * @param $message Some text describing the exception
+ * @param $code Some code describing the exception
+ */
+ function __construct($message = NULL, $code = 0) {
+ if (func_num_args()) {
+ $this->message = $message;
+ }
+ $this->code = $code;
+ $this->file = __FILE__; // of throw clause
+ $this->line = __LINE__; // of throw clause
+ $this->trace = debug_backtrace();
+ $this->string = StringFormat($this);
+ }
+
+ /** @return the message passed to the constructor
+ */
+ final public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /** @return the code passed to the constructor
+ */
+ final public function getCode()
+ {
+ return $this->code;
+ }
+
+ /** @return the name of the file where the exception was thrown
+ */
+ final public function getFile()
+ {
+ return $this->file;
+ }
+
+ /** @return the line number where the exception was thrown
+ */
+ final public function getLine()
+ {
+ return $this->line;
+ }
+
+ /** @return the stack trace as array
+ */
+ final public function getTrace()
+ {
+ return $this->trace;
+ }
+
+ /** @return the stack trace as string
+ */
+ final public function getTraceAsString()
+ {
+ }
+
+ /** @return string represenation of exception
+ */
+ public function __toString()
+ {
+ return $this->string;
+ }
+}
+
+/** @ingroup SPL
+ * @brief Exception that represents error in the program logic.
+ * @since PHP 5.1
+ *
+ * This kind of exceptions should directly leed to a fix in your code.
+ */
+class LogicException extends Exception
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown when a function call was illegal.
+ * @since PHP 5.1
+ */
+class BadFunctionCallException extends LogicException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown when a method call was illegal.
+ * @since PHP 5.1
+ */
+class BadMethodCallException extends BadFunctionCallException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception that denotes a value not in the valid domain was used.
+ * @since PHP 5.1
+ *
+ * This kind of exception should be used to inform about domain erors in
+ * mathematical sense.
+ *
+ * @see RangeException
+ */
+class DomainException extends LogicException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception that denotes invalid arguments were passed.
+ * @since PHP 5.1
+ *
+ * @see UnexpectedValueException
+ */
+class InvalidArgumentException extends LogicException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown when a parameter exceeds the allowed length.
+ * @since PHP 5.1
+ *
+ * This can be used for strings length, array size, file size, number of
+ * elements read from an Iterator and so on.
+ */
+class LengthException extends LogicException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown when an illegal index was requested.
+ * @since PHP 5.1
+ *
+ * This represents errors that should be detected at compile time.
+ *
+ * @see OutOfBoundsException
+ */
+class OutOfRangeException extends LogicException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown for errors that are only detectable at runtime.
+ * @since PHP 5.1
+ */
+class RuntimeException extends Exception
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown when an illegal index was requested.
+ * @since PHP 5.1
+ *
+ * This represents errors that cannot be detected at compile time.
+ *
+ * @see OutOfRangeException
+ */
+class OutOfBoundsException extends RuntimeException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown to indicate arithmetic/buffer overflow.
+ * @since PHP 5.1
+ */
+class OverflowException extends RuntimeException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown to indicate range errors during program execution.
+ * @since PHP 5.1
+ *
+ * Normally this means there was an arithmetic error other than under/overflow.
+ * This is the runtime version of DomainException.
+ *
+ * @see DomainException
+ */
+class RangeException extends RuntimeException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown to indicate arithmetic/buffer underflow.
+ * @since PHP 5.1
+ */
+class UnderflowException extends RuntimeException
+{
+}
+
+/** @ingroup SPL
+ * @brief Exception thrown to indicate an unexpected value.
+ * @since PHP 5.1
+ *
+ * Typically this happens when a function calls another function and espects
+ * the return value to be of a certain type or value not including arithmetic
+ * or buffer related errors.
+ *
+ * @see InvalidArgumentException
+ */
+class UnexpectedValueException extends RuntimeException
+{
+}
+
+/** @ingroup ZendEngine
+ * @brief Interface to override array access of objects.
+ * @since PHP 5.0
+ */
+interface ArrayAccess
+{
+ /** @param $offset to modify
+ * @param $value new value
+ */
+ function offsetSet($offset, $value);
+
+ /** @param $offset to retrieve
+ * @return value at given offset
+ */
+ function offsetGet($offset);
+
+ /** @param $offset to delete
+ */
+ function offsetUnset($offset);
+
+ /** @param $offset to check
+ * @return whether the offset exists.
+ */
+ function offsetExists($offset);
+}
+
+/** @ingroup ZendEngine
+ * @brief Interface to detect a class is traversable using foreach.
+ * @since PHP 5.0
+ *
+ * Abstract base interface that cannot be implemented alone. Instead it
+ * must be implemented by either IteratorAggregate or Iterator.
+ *
+ * @note Internal classes that implement this interface can be used in a
+ * foreach construct and do not need to implement IteratorAggregate or
+ * Iterator.
+ *
+ * @note This is an engine internal interface which cannot be implemented
+ * in PHP scripts. Either IteratorAggregate or Iterator must be used
+ * instead.
+ */
+interface Traversable
+{
+}
+
+/** @ingroup ZendEngine
+ * @brief Interface to create an external Iterator.
+ * @since PHP 5.0
+ *
+ * @note This is an engine internal interface.
+ */
+interface IteratorAggregate extends Traversable
+{
+ /** @return an Iterator for the implementing object.
+ */
+ function getIterator();
+}
+
+/** @ingroup ZendEngine
+ * @brief Basic iterator
+ * @since PHP 5.0
+ *
+ * Interface for external iterators or objects that can be iterated
+ * themselves internally.
+ *
+ * @note This is an engine internal interface.
+ */
+interface Iterator extends Traversable
+{
+ /** Rewind the Iterator to the first element.
+ */
+ function rewind();
+
+ /** Return the current element.
+ */
+ function current();
+
+ /** Return the key of the current element.
+ */
+ function key();
+
+ /** Move forward to next element.
+ */
+ function next();
+
+ /** Check if there is a current element after calls to rewind() or next().
+ */
+ function valid();
+}
+
+/** @ingroup SPL
+ * @brief This Interface allows to hook into the global count() function.
+ * @since PHP 5.1
+ */
+interface Countable
+{
+ /** @return the number the global function count() should show
+ */
+ function count();
+}
+
+/** @ingroup ZendEngine
+ * @brief Interface for customized serializing
+ * @since 5.1
+ *
+ * Classes that implement this interface no longer support __sleep() and
+ * __wakeup(). The method serialized is called whenever an instance needs to
+ * be serialized. This does not invoke __destruct() or has any other side
+ * effect unless programmed inside the method. When the data is unserialized
+ * the class is known and the appropriate unserialize() method is called as a
+ * constructor instead of calling __construct(). If you need to execute the
+ * standard constructor you may do so in the method.
+ */
+interface Serializable
+{
+ /**
+ * @return string representation of the instance
+ */
+ function serialize();
+
+ /**
+ * @note This is a constructor
+ *
+ * @param $serialized data read from stream to construct the instance
+ */
+ function unserialize($serialized);
+}
+
+/** @ingroup SPL
+ * @brief An Array wrapper
+ * @since PHP 5.0
+ * @version 1.2
+ *
+ * This array wrapper allows to recursively iterate over Arrays and public
+ * Object properties.
+ *
+ * @see ArrayIterator
+ */
+class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
+{
+ /** Properties of the object have their normal functionality
+ * when accessed as list (var_dump, foreach, etc.) */
+ const STD_PROP_LIST = 0x00000001;
+ /** Array indices can be accessed as properties in read/write */
+ const ARRAY_AS_PROPS = 0x00000002;
+
+ /** Construct a new array iterator from anything that has a hash table.
+ * That is any Array or Object.
+ *
+ * @param $array the array to use.
+ * @param $flags see setFlags().
+ * @param $iterator_class class used in getIterator()
+ */
+ function __construct($array, $flags = 0, $iterator_class = "ArrayIterator") {/**/}
+
+ /** Set behavior flags.
+ *
+ * @param $flags bitmask as follows:
+ * 0 set: properties of the object have their normal functionality
+ * when accessed as list (var_dump, foreach, etc.)
+ * 1 set: array indices can be accessed as properties in read/write
+ */
+ function setFlags($flags) {/**/}
+
+ /** @return current flags
+ */
+ function getFlags() {/**/}
+
+ /** Sort the entries by values.
+ */
+ function asort() {/**/}
+
+ /** Sort the entries by key.
+ */
+ function ksort() {/**/}
+
+ /** Sort the entries by values using user defined function.
+ */
+ function uasort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by key using user defined function.
+ */
+ function uksort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by values using "natural order" algorithm.
+ */
+ function natsort() {/**/}
+
+ /** Sort the entries by values using case insensitive "natural order" algorithm.
+ */
+ function natcasesort() {/**/}
+
+ /** @param $array new array or object
+ */
+ function exchangeArray($array) {/**/}
+
+ /** @return the iterator which is an ArrayIterator object connected to
+ * this object.
+ */
+ function getIterator() {/**/}
+
+ /** @param $index offset to inspect
+ * @return whetehr offset $index esists
+ */
+ function offsetExists($index) {/**/}
+
+ /** @param $index offset to return value for
+ * @return value at offset $index
+ */
+ function offsetGet($index) {/**/}
+
+ /** @param $index index to set
+ * @param $newval new value to store at offset $index
+ */
+ function offsetSet($index, $newval) {/**/}
+
+ /** @param $index offset to unset
+ */
+ function offsetUnset($index) {/**/}
+
+ /** @param $value is appended as last element
+ * @warning this method cannot be called when the ArrayObject refers to
+ * an object.
+ */
+ function append($value) {/**/}
+
+ /** @return a \b copy of the array
+ * @note when the ArrayObject refers to an object then this method
+ * returns an array of the public properties.
+ */
+ function getArrayCopy() {/**/}
+
+ /** @return the number of elements in the array or the number of public
+ * properties in the object.
+ */
+ function count() {/**/}
+
+ /* @param $iterator_class new class used in getIterator()
+ */
+ function setIteratorClass($itertor_class) {/**/}
+
+ /* @return class used in getIterator()
+ */
+ function getIteratorClass() {/**/}
+}
+
+/** @ingroup SPL
+ * @brief An Array iterator
+ * @since PHP 5.0
+ * @version 1.2
+ *
+ * This iterator allows to unset and modify values and keys while iterating
+ * over Arrays and Objects.
+ *
+ * When you want to iterate over the same array multiple times you need to
+ * instanciate ArrayObject and let it create ArrayIterator instances that
+ * refer to it either by using foreach or by calling its getIterator()
+ * method manually.
+ */
+class ArrayIterator implements SeekableIterator, ArrayAccess, Countable
+{
+ /** Properties of the object have their normal functionality
+ * when accessed as list (var_dump, foreach, etc.) */
+ const STD_PROP_LIST = 0x00000001;
+ /** Array indices can be accessed as properties in read/write */
+ const ARRAY_AS_PROPS = 0x00000002;
+
+ /** Construct a new array iterator from anything that has a hash table.
+ * That is any Array or Object.
+ *
+ * @param $array the array to use.
+ * @param $flags see setFlags().
+ */
+ function __construct($array, $flags = 0) {/**/}
+
+ /** Set behavior flags.
+ *
+ * @param $flags bitmask as follows:
+ * 0 set: properties of the object have their normal functionality
+ * when accessed as list (var_dump, foreach, etc.)
+ * 1 set: array indices can be accessed as properties in read/write
+ */
+ function setFlags($flags) {/**/}
+
+ /**
+ * @return current flags
+ */
+ function getFlags() {/**/}
+
+ /** Sort the entries by values.
+ */
+ function asort() {/**/}
+
+ /** Sort the entries by key.
+ */
+ function ksort() {/**/}
+
+ /** Sort the entries by values using user defined function.
+ */
+ function uasort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by key using user defined function.
+ */
+ function uksort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by values using "natural order" algorithm.
+ */
+ function natsort() {/**/}
+
+ /** Sort the entries by values using case insensitive "natural order" algorithm.
+ */
+ function natcasesort() {/**/}
+
+ /** @param $index offset to inspect
+ * @return whetehr offset $index esists
+ */
+ function offsetExists($index) {/**/}
+
+ /** @param $index offset to return value for
+ * @return value at offset $index
+ */
+ function offsetGet($index) {/**/}
+
+ /** @param $index index to set
+ * @param $newval new value to store at offset $index
+ */
+ function offsetSet($index, $newval) {/**/}
+
+ /** @param $index offset to unset
+ */
+ function offsetUnset($index) {/**/}
+
+ /** @param $value is appended as last element
+ * @warning this method cannot be called when the ArrayIterator refers to
+ * an object.
+ */
+ function append($value) {/**/}
+
+ /** @return a \b copy of the array
+ * @note when the ArrayIterator refers to an object then this method
+ * returns an array of the public properties.
+ */
+ function getArrayCopy() {/**/}
+
+ /** @param $position offset to seek to
+ * @throw OutOfBoundsException if $position is invalid
+ */
+ function seek($position) {/**/}
+
+ /** @return the number of elements in the array or the number of public
+ * properties in the object.
+ */
+ function count() {/**/}
+
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
+ /** @copydoc Iterator::current */
+ function current() {/**/}
+
+ /** @copydoc Iterator::key */
+ function key() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
+}
+
+/** @ingroup SPL
+ * @brief File info class
+ * @since PHP 5.1.3
+ */
+class SplFileInfo
+{
+ /** Construct a file info object
+ *
+ * @param $file_name path or file name
+ */
+ function __construct($file_name) {/**/}
+
+ /** @return the path part only.
+ */
+ function getPath() {/**/}
+
+ /** @return the filename only.
+ */
+ function getFilename() {/**/}
+
+ /** @return SplFileInfo created for the file
+ * @param class_name name of class to instantiate
+ * @see SplFileInfo::setInfoClass()
+ */
+ function getFileInfo(string class_name = NULL) {/**/}
+
+ /** @return The current entries path and file name.
+ */
+ function getPathname() {/**/}
+
+ /** @return SplFileInfo created for the path
+ * @param class_name name of class to instantiate
+ * @see SplFileInfo::setInfoClass()
+ */
+ function getPathInfo(string class_name = NULL) {/**/}
+
+ /** @return The current entry's permissions.
+ */
+ function getPerms() {/**/}
+
+ /** @return The current entry's inode.
+ */
+ function getInode() {/**/}
+
+ /** @return The current entry's size in bytes .
+ */
+ function getSize() {/**/}
+
+ /** @return The current entry's owner name.
+ */
+ function getOwner() {/**/}
+
+ /** @return The current entry's group name.
+ */
+ function getGroup() {/**/}
+
+ /** @return The current entry's last access time.
+ */
+ function getATime() {/**/}
+
+ /** @return The current entry's last modification time.
+ */
+ function getMTime() {/**/}
+
+ /** @return The current entry's last change time.
+ */
+ function getCTime() {/**/}
+
+ /** @return The current entry's file type.
+ */
+ function getType() {/**/}
+
+ /** @return Whether the current entry is writeable.
+ */
+ function isWritable() {/**/}
+
+ /** @return Whether the current entry is readable.
+ */
+ function isReadable() {/**/}
+
+ /** @return Whether the current entry is executable.
+ */
+ function isExecutable() {/**/}
+
+ /** @return Whether the current entry is .
+ */
+ function isFile() {/**/}
+
+ /** @return Whether the current entry is a directory.
+ */
+ function isDir() {/**/}
+
+ /** @return whether the current entry is a link.
+ */
+ function isLink() {/**/}
+
+ /** @return target of link.
+ */
+ function getLinkTarget() {/**/}
+
+ /** @return The resolved path
+ */
+ function getRealPath() {/**/}
+
+ /** @return getPathname()
+ */
+ function __toString() {/**/}
+
+ /** Open the current file as a SplFileObject instance
+ *
+ * @param mode open mode
+ * @param use_include_path whether to search include paths (don't use)
+ * @param context resource context to pased to open function
+ * @throw RuntimeException if file cannot be opened (e.g. insufficient
+ * access rights).
+ * @return The opened file as a SplFileObject instance
+ *
+ * @see SplFileObject
+ * @see SplFileInfo::setFileClass()
+ * @see file()
+ */
+ function openFile($mode = 'r', $use_include_path = false, $context = NULL) {/**/}
+
+ /** @param class_name name of class used with openFile(). Must be derived
+ * from SPLFileObject.
+ */
+ function setFileClass(string class_name = "SplFileObject") {/**/}
+
+ /** @param class_name name of class used with getFileInfo(), getPathInfo().
+ * Must be derived from SplFileInfo.
+ */
+ function setInfoClass(string class_name = "SplFileInfo") {/**/}
+}
+
+/** @ingroup SPL
+ * @brief Directory iterator
+ * @version 1.1
+ * @since PHP 5.0
+ */
+class DirectoryIterator extends SplFileInfo implements Iterator
+{
+ /** Construct a directory iterator from a path-string.
+ *
+ * @param $path directory to iterate.
+ */
+ function __construct($path) {/**/}
+
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
+ /** @return index of entry
+ */
+ function key() {/**/}
+
+ /** @return $this
+ */
+ function current() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
+
+ /** @return Whether the current entry is either '.' or '..'.
+ */
+ function isDot() {/**/}
+
+ /** @return whether the current entry is a link.
+ */
+ function isLink() {/**/}
+
+ /** @return getFilename()
+ */
+ function __toString() {/**/}
+}
+
+/** @ingroup SPL
+ * @brief recursive directory iterator
+ * @version 1.1
+ * @since PHP 5.0
+ */
+class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveIterator
+{
+ const CURRENT_AS_FILEINFO 0x00000000; /* make RecursiveDirectoryTree::current() return SplFileInfo */
+ const CURRENT_AS_SELF 0x00000010; /* make RecursiveDirectoryTree::current() return getSelf() */
+ const CURRENT_AS_PATHNAME 0x00000020; /* make RecursiveDirectoryTree::current() return getPathname() */
+
+ const KEY_AS_PATHNAME 0x00000000; /* make RecursiveDirectoryTree::key() return getPathname() */
+ const KEY_AS_FILENAME 0x00000100; /* make RecursiveDirectoryTree::key() return getFilename() */
+
+ const NEW_CURRENT_AND_KEY 0x00000100; /* CURRENT_AS_FILEINFO + KEY_AS_FILENAME */
+
+ /** Construct a directory iterator from a path-string.
+ *
+ * @param $path directory to iterate.
+ * @param $flags open flags
+ * - CURRENT_AS_FILEINFO
+ * - CURRENT_AS_SELF
+ * - CURRENT_AS_PATHNAME
+ * - KEY_AS_PATHNAME
+ * - KEY_AS_FILENAME
+ * - NEW_CURRENT_AND_KEY
+ */
+ function __construct($path, $flags = 0) {/**/}
+
+ /** @return getPathname() or getFilename() depending on flags
+ */
+ function key() {/**/}
+
+ /** @return getFilename() or getFileInfo() depending on flags
+ */
+ function current() {/**/}
+
+ /** @return whether the current is a directory (not '.' or '..').
+ */
+ function hasChildren() {/**/}
+
+ /** @return a RecursiveDirectoryIterator for the current entry.
+ */
+ function getChildren() {/**/}
+
+ /** @return sub path only (without main path)
+ */
+ function getSubPath() {/**/}
+
+ /** @return the current sub path
+ */
+ function getSubPathname() {/**/}
+}
+
+/** @ingroup SPL
+ * @brief recursive SimpleXML_Element iterator
+ * @since PHP 5.0
+ *
+ * The SimpleXMLIterator implements the RecursiveIterator interface. This
+ * allows iteration over all elements using foreach or an appropriate while
+ * construct, just like SimpleXMLElement does. When using the foreach construct,
+ * you will also iterate over the subelements. For every element which
+ * has subelements, hasChildren() returns true. This will trigger a call to
+ * getChildren() which returns the iterator for that sub element.
+ */
+class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator, Countable
+{
+ /** @return whether the current node has sub nodes.
+ */
+ function hasChildren() {/**/}
+
+ /** @return a SimpleXMLIterator for the current node.
+ */
+ function getChildren() {/**/}
+
+ /** @return number of elements/attributes seen with foreach()
+ */
+ function count() {/**/}
+
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
+ /** @copydoc Iterator::current */
+ function current() {/**/}
+
+ /** @copydoc Iterator::key */
+ function key() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
+}
+
+/** @ingroup SPL
+ * @brief Observer of the observer pattern
+ * @since PHP 5.1
+ *
+ * For a detailed explanation see Observer pattern in
+ * <em>
+ * Gamma, Helm, Johnson, Vlissides<br />
+ * Design Patterns
+ * </em>
+ */
+interface SplObserver
+{
+ /** Called from the subject (i.e. when it's value has changed).
+ * @param $subject the callee
+ */
+ function update(SplSubject $subject);
+}
+
+/** @ingroup SPL
+ * @brief Subject to the observer pattern
+ * @since PHP 5.1
+ * @see Observer
+ */
+interface SplSubject
+{
+ /** @param $observer new observer to attach
+ */
+ function attach(SplObserver $observer);
+
+ /** @param $observer existing observer to detach
+ * @note a non attached observer shouldn't result in a warning or similar
+ */
+ function detach(SplObserver $observer);
+
+ /** Notify all observers
+ */
+ function notify();
+}
+
+?>
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
new file mode 100644
index 0000000..2c2c87d
--- /dev/null
+++ b/ext/spl/spl_array.c
@@ -0,0 +1,1995 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/php_smart_str.h"
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+#include "spl_array.h"
+#include "spl_exceptions.h"
+
+zend_object_handlers spl_handler_ArrayObject;
+PHPAPI zend_class_entry *spl_ce_ArrayObject;
+
+zend_object_handlers spl_handler_ArrayIterator;
+PHPAPI zend_class_entry *spl_ce_ArrayIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
+
+#define SPL_ARRAY_STD_PROP_LIST 0x00000001
+#define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
+#define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004
+#define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
+#define SPL_ARRAY_OVERLOADED_VALID 0x00020000
+#define SPL_ARRAY_OVERLOADED_KEY 0x00040000
+#define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
+#define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
+#define SPL_ARRAY_IS_REF 0x01000000
+#define SPL_ARRAY_IS_SELF 0x02000000
+#define SPL_ARRAY_USE_OTHER 0x04000000
+#define SPL_ARRAY_INT_MASK 0xFFFF0000
+#define SPL_ARRAY_CLONE_MASK 0x0300FFFF
+
+#define SPL_ARRAY_METHOD_NO_ARG 0
+#define SPL_ARRAY_METHOD_USE_ARG 1
+#define SPL_ARRAY_METHOD_MAY_USER_ARG 2
+
+typedef struct _spl_array_object {
+ zend_object std;
+ zval *array;
+ zval *retval;
+ HashPosition pos;
+ ulong pos_h;
+ int ar_flags;
+ int is_self;
+ zend_function *fptr_offset_get;
+ zend_function *fptr_offset_set;
+ zend_function *fptr_offset_has;
+ zend_function *fptr_offset_del;
+ zend_function *fptr_count;
+ zend_class_entry* ce_get_iterator;
+ HashTable *debug_info;
+ unsigned char nApplyCount;
+} spl_array_object;
+
+static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
+ if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ return intern->std.properties;
+ } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
+ spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
+ return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
+ } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ return intern->std.properties;
+ } else {
+ return HASH_OF(intern->array);
+ }
+} /* }}} */
+
+static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
+
+static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
+{
+ Bucket *pos = intern->pos;
+ if (pos != NULL) {
+ intern->pos_h = pos->h;
+ }
+} /* }}} */
+
+static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
+{
+ intern->pos = pos;
+ spl_array_update_pos(intern);
+} /* }}} */
+
+SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
+{
+ Bucket *p;
+
+/* IS_CONSISTENT(ht);*/
+
+/* HASH_PROTECT_RECURSION(ht);*/
+ p = ht->arBuckets[intern->pos_h & ht->nTableMask];
+ while (p != NULL) {
+ if (p == intern->pos) {
+ return SUCCESS;
+ }
+ p = p->pNext;
+ }
+/* HASH_UNPROTECT_RECURSION(ht); */
+ spl_array_rewind(intern TSRMLS_CC);
+ return FAILURE;
+
+} /* }}} */
+
+SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
+{
+ HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_array_object_free_storage */
+static void spl_array_object_free_storage(void *object TSRMLS_DC)
+{
+ spl_array_object *intern = (spl_array_object *)object;
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+
+ zval_ptr_dtor(&intern->array);
+ zval_ptr_dtor(&intern->retval);
+
+ if (intern->debug_info != NULL) {
+ zend_hash_destroy(intern->debug_info);
+ efree(intern->debug_info);
+ }
+
+ efree(object);
+}
+/* }}} */
+
+zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
+
+/* {{{ spl_array_object_new_ex */
+static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
+{
+ zend_object_value retval;
+ spl_array_object *intern;
+ zval *tmp;
+ zend_class_entry * parent = class_type;
+ int inherited = 0;
+
+ intern = emalloc(sizeof(spl_array_object));
+ memset(intern, 0, sizeof(spl_array_object));
+ *obj = intern;
+ ALLOC_INIT_ZVAL(intern->retval);
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ intern->ar_flags = 0;
+ intern->debug_info = NULL;
+ intern->ce_get_iterator = spl_ce_ArrayIterator;
+ if (orig) {
+ spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
+
+ intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
+ intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
+ intern->ce_get_iterator = other->ce_get_iterator;
+ if (clone_orig) {
+ intern->array = other->array;
+ if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
+ MAKE_STD_ZVAL(intern->array);
+ array_init(intern->array);
+ zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
+ }
+ if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
+ Z_ADDREF_P(other->array);
+ }
+ } else {
+ intern->array = orig;
+ Z_ADDREF_P(intern->array);
+ intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
+ }
+ } else {
+ MAKE_STD_ZVAL(intern->array);
+ array_init(intern->array);
+ intern->ar_flags &= ~SPL_ARRAY_IS_REF;
+ }
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
+ while (parent) {
+ if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
+ retval.handlers = &spl_handler_ArrayIterator;
+ class_type->get_iterator = spl_array_get_iterator;
+ break;
+ } else if (parent == spl_ce_ArrayObject) {
+ retval.handlers = &spl_handler_ArrayObject;
+ break;
+ }
+ parent = parent->parent;
+ inherited = 1;
+ }
+ if (!parent) { /* this must never happen */
+ php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
+ }
+ if (inherited) {
+ zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
+ if (intern->fptr_offset_get->common.scope == parent) {
+ intern->fptr_offset_get = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
+ if (intern->fptr_offset_set->common.scope == parent) {
+ intern->fptr_offset_set = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
+ if (intern->fptr_offset_has->common.scope == parent) {
+ intern->fptr_offset_has = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
+ if (intern->fptr_offset_del->common.scope == parent) {
+ intern->fptr_offset_del = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
+ if (intern->fptr_count->common.scope == parent) {
+ intern->fptr_count = NULL;
+ }
+ }
+ /* Cache iterator functions if ArrayIterator or derived. Check current's */
+ /* cache since only current is always required */
+ if (retval.handlers == &spl_handler_ArrayIterator) {
+ if (!class_type->iterator_funcs.zf_current) {
+ zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
+ zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
+ zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
+ zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
+ zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
+ }
+ if (inherited) {
+ if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
+ if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
+ if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
+ if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
+ if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
+ }
+ }
+
+ spl_array_rewind(intern TSRMLS_CC);
+ return retval;
+}
+/* }}} */
+
+/* {{{ spl_array_object_new */
+static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ spl_array_object *tmp;
+ return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_array_object_clone */
+static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_array_object *intern;
+
+ old_object = zend_objects_get_address(zobject TSRMLS_CC);
+ new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
+ new_object = &intern->std;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ return new_obj_val;
+}
+/* }}} */
+
+static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ zval **retval;
+ long index;
+ HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (!offset) {
+ return &EG(uninitialized_zval_ptr);
+ }
+
+ if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return &EG(error_zval_ptr);;
+ }
+
+ switch(Z_TYPE_P(offset)) {
+ case IS_NULL:
+ Z_STRVAL_P(offset) = "";
+ Z_STRLEN_P(offset) = 0;
+ case IS_STRING:
+ if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
+ switch (type) {
+ case BP_VAR_R:
+ zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset));
+ case BP_VAR_UNSET:
+ case BP_VAR_IS:
+ retval = &EG(uninitialized_zval_ptr);
+ break;
+ case BP_VAR_RW:
+ zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
+ case BP_VAR_W: {
+ zval *value;
+ ALLOC_INIT_ZVAL(value);
+ zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), (void **)&retval);
+ }
+ }
+ }
+ return retval;
+ case IS_RESOURCE:
+ zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(offset), Z_LVAL_P(offset));
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (offset->type == IS_DOUBLE) {
+ index = (long)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
+ switch (type) {
+ case BP_VAR_R:
+ zend_error(E_NOTICE, "Undefined offset: %ld", index);
+ case BP_VAR_UNSET:
+ case BP_VAR_IS:
+ retval = &EG(uninitialized_zval_ptr);
+ break;
+ case BP_VAR_RW:
+ zend_error(E_NOTICE, "Undefined offset: %ld", index);
+ case BP_VAR_W: {
+ zval *value;
+ ALLOC_INIT_ZVAL(value);
+ zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), (void **)&retval);
+ }
+ }
+ }
+ return retval;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ return (type == BP_VAR_W || type == BP_VAR_RW) ?
+ &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
+ }
+} /* }}} */
+
+static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
+{
+ zval **ret;
+
+ if (check_inherited) {
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (intern->fptr_offset_get) {
+ zval *rv;
+ if (!offset) {
+ ALLOC_INIT_ZVAL(offset);
+ } else {
+ SEPARATE_ARG_IF_REF(offset);
+ }
+ zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
+ zval_ptr_dtor(&offset);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ return intern->retval;
+ }
+ return EG(uninitialized_zval_ptr);
+ }
+ }
+ ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
+
+ /* When in a write context,
+ * ZE has to be fooled into thinking this is in a reference set
+ * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
+ if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) && !Z_ISREF_PP(ret)) {
+ if (Z_REFCOUNT_PP(ret) > 1) {
+ zval *newval;
+
+ /* Separate */
+ MAKE_STD_ZVAL(newval);
+ *newval = **ret;
+ zval_copy_ctor(newval);
+ Z_SET_REFCOUNT_P(newval, 1);
+
+ /* Replace */
+ Z_DELREF_PP(ret);
+ *ret = newval;
+ }
+
+ Z_SET_ISREF_PP(ret);
+ }
+
+ return *ret;
+} /* }}} */
+
+static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
+{
+ return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
+} /* }}} */
+
+static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ long index;
+ HashTable *ht;
+
+ if (check_inherited && intern->fptr_offset_set) {
+ if (!offset) {
+ ALLOC_INIT_ZVAL(offset);
+ } else {
+ SEPARATE_ARG_IF_REF(offset);
+ }
+ zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
+ zval_ptr_dtor(&offset);
+ return;
+ }
+
+ if (!offset) {
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ Z_ADDREF_P(value);
+ zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
+ return;
+ }
+ switch(Z_TYPE_P(offset)) {
+ case IS_STRING:
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ Z_ADDREF_P(value);
+ zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
+ return;
+ case IS_DOUBLE:
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ if (offset->type == IS_DOUBLE) {
+ index = (long)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ Z_ADDREF_P(value);
+ zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
+ return;
+ case IS_NULL:
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ Z_ADDREF_P(value);
+ zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
+ return;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ return;
+ }
+} /* }}} */
+
+static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
+{
+ spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
+} /* }}} */
+
+static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ long index;
+ HashTable *ht;
+
+ if (check_inherited && intern->fptr_offset_del) {
+ SEPARATE_ARG_IF_REF(offset);
+ zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
+ zval_ptr_dtor(&offset);
+ return;
+ }
+
+ switch(Z_TYPE_P(offset)) {
+ case IS_STRING:
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ if (ht == &EG(symbol_table)) {
+ if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
+ zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
+ }
+ } else {
+ if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
+ zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
+ } else {
+ spl_array_object *obj = intern;
+
+ while (1) {
+ if ((obj->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
+ break;
+ } else if (Z_TYPE_P(obj->array) == IS_OBJECT) {
+ if ((obj->ar_flags & SPL_ARRAY_USE_OTHER) == 0) {
+ obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
+ break;
+ } else {
+ obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
+ }
+ } else {
+ obj = NULL;
+ break;
+ }
+ }
+ if (obj) {
+ zend_property_info *property_info = zend_get_property_info(obj->std.ce, offset, 1 TSRMLS_CC);
+
+ if (property_info &&
+ (property_info->flags & ZEND_ACC_STATIC) == 0 &&
+ property_info->offset >= 0) {
+ obj->std.properties_table[property_info->offset] = NULL;
+ }
+ }
+ }
+ }
+ break;
+ case IS_DOUBLE:
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ if (offset->type == IS_DOUBLE) {
+ index = (long)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (ht->nApplyCount > 0) {
+ zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
+ return;
+ }
+ if (zend_hash_index_del(ht, index) == FAILURE) {
+ zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
+ }
+ break;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ return;
+ }
+ spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
+} /* }}} */
+
+static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
+{
+ spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
+} /* }}} */
+
+static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ long index;
+ zval *rv, **tmp;
+
+ if (check_inherited && intern->fptr_offset_has) {
+ SEPARATE_ARG_IF_REF(offset);
+ zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
+ zval_ptr_dtor(&offset);
+ if (rv && zend_is_true(rv)) {
+ zval_ptr_dtor(&rv);
+ return 1;
+ }
+ if (rv) {
+ zval_ptr_dtor(&rv);
+ }
+ return 0;
+ }
+
+ switch(Z_TYPE_P(offset)) {
+ case IS_STRING:
+ {
+ HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) {
+ switch (check_empty) {
+ case 0:
+ return Z_TYPE_PP(tmp) != IS_NULL;
+ case 2:
+ return 1;
+ default:
+ return zend_is_true(*tmp);
+ }
+ }
+ }
+ return 0;
+ case IS_DOUBLE:
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ {
+ HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ if (offset->type == IS_DOUBLE) {
+ index = (long)Z_DVAL_P(offset);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+ if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
+ switch (check_empty) {
+ case 0:
+ return Z_TYPE_PP(tmp) != IS_NULL;
+ case 2:
+ return 1;
+ default:
+ return zend_is_true(*tmp);
+ }
+ }
+ return 0;
+ }
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ }
+ return 0;
+} /* }}} */
+
+static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
+{
+ return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
+} /* }}} */
+
+/* {{{ spl_array_object_verify_pos_ex */
+static inline int spl_array_object_verify_pos_ex(spl_array_object *object, HashTable *ht, const char *msg_prefix TSRMLS_DC)
+{
+ if (!ht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and is no longer an array", msg_prefix);
+ return FAILURE;
+ }
+
+ if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, ht TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and internal position is no longer valid", msg_prefix);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+/* {{{ spl_array_object_verify_pos */
+static inline int spl_array_object_verify_pos(spl_array_object *object, HashTable *ht TSRMLS_DC)
+{
+ return spl_array_object_verify_pos_ex(object, ht, "" TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool ArrayObject::offsetExists(mixed $index)
+ proto bool ArrayIterator::offsetExists(mixed $index)
+ Returns whether the requested $index exists. */
+SPL_METHOD(Array, offsetExists)
+{
+ zval *index;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
+ return;
+ }
+ RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 2 TSRMLS_CC));
+} /* }}} */
+
+/* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
+ proto mixed ArrayIterator::offsetGet(mixed $index)
+ Returns the value at the specified $index. */
+SPL_METHOD(Array, offsetGet)
+{
+ zval *index, *value;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
+ return;
+ }
+ value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
+ RETURN_ZVAL(value, 1, 0);
+} /* }}} */
+
+/* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
+ proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
+ Sets the value at the specified $index to $newval. */
+SPL_METHOD(Array, offsetSet)
+{
+ zval *index, *value;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
+ return;
+ }
+ spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
+} /* }}} */
+
+void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ if (Z_TYPE_P(intern->array) == IS_OBJECT) {
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
+ return;
+ }
+
+ spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
+ if (!intern->pos) {
+ spl_array_set_pos(intern, aht->pListTail);
+ }
+} /* }}} */
+
+/* {{{ proto void ArrayObject::append(mixed $newval)
+ proto void ArrayIterator::append(mixed $newval)
+ Appends the value (cannot be called for objects). */
+SPL_METHOD(Array, append)
+{
+ zval *value;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+ return;
+ }
+ spl_array_iterator_append(getThis(), value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void ArrayObject::offsetUnset(mixed $index)
+ proto void ArrayIterator::offsetUnset(mixed $index)
+ Unsets the value at the specified $index. */
+SPL_METHOD(Array, offsetUnset)
+{
+ zval *index;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
+ return;
+ }
+ spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto array ArrayObject::getArrayCopy()
+ proto array ArrayIterator::getArrayCopy()
+ Return a copy of the contained array */
+SPL_METHOD(Array, getArrayCopy)
+{
+ zval *object = getThis(), *tmp;
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ array_init(return_value);
+ zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
+} /* }}} */
+
+static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *result;
+
+ if (intern->nApplyCount > 1) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
+ }
+
+ intern->nApplyCount++;
+ result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
+ intern->nApplyCount--;
+ return result;
+} /* }}} */
+
+static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ zval *tmp, *storage;
+ int name_len;
+ char *zname;
+ zend_class_entry *base;
+
+ *is_temp = 0;
+
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+
+ if (HASH_OF(intern->array) == intern->std.properties) {
+ return intern->std.properties;
+ } else {
+ if (intern->debug_info == NULL) {
+ ALLOC_HASHTABLE(intern->debug_info);
+ ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
+ }
+
+ if (intern->debug_info->nApplyCount == 0) {
+ zend_hash_clean(intern->debug_info);
+ zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ storage = intern->array;
+ zval_add_ref(&storage);
+
+ base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
+ zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
+ zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
+ efree(zname);
+ }
+
+ return intern->debug_info;
+ }
+}
+/* }}} */
+
+static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
+ && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
+ return spl_array_read_dimension(object, member, type TSRMLS_CC);
+ }
+ return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
+} /* }}} */
+
+static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
+ && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
+ spl_array_write_dimension(object, member, value TSRMLS_CC);
+ return;
+ }
+ std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
+} /* }}} */
+
+static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
+ && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
+ return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC);
+ }
+ return std_object_handlers.get_property_ptr_ptr(object, member, key TSRMLS_CC);
+} /* }}} */
+
+static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
+ && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
+ return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
+ }
+ return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC);
+} /* }}} */
+
+static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
+ && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
+ spl_array_unset_dimension(object, member TSRMLS_CC);
+ spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
+ return;
+ }
+ std_object_handlers.unset_property(object, member, key TSRMLS_CC);
+} /* }}} */
+
+static int spl_array_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
+{
+ HashTable *ht1,
+ *ht2;
+ spl_array_object *intern1,
+ *intern2;
+ int result = 0;
+ zval temp_zv;
+
+ intern1 = (spl_array_object*)zend_object_store_get_object(o1 TSRMLS_CC);
+ intern2 = (spl_array_object*)zend_object_store_get_object(o2 TSRMLS_CC);
+ ht1 = spl_array_get_hash_table(intern1, 0 TSRMLS_CC);
+ ht2 = spl_array_get_hash_table(intern2, 0 TSRMLS_CC);
+
+ zend_compare_symbol_tables(&temp_zv, ht1, ht2 TSRMLS_CC);
+ result = (int)Z_LVAL(temp_zv);
+ /* if we just compared std.properties, don't do it again */
+ if (result == 0 &&
+ !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
+ result = std_object_handlers.compare_objects(o1, o2 TSRMLS_CC);
+ }
+ return result;
+} /* }}} */
+
+static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
+{
+ char *string_key;
+ uint string_length;
+ ulong num_key;
+
+ if (Z_TYPE_P(intern->array) == IS_OBJECT) {
+ do {
+ if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
+ if (!string_length || string_key[0]) {
+ return SUCCESS;
+ }
+ } else {
+ return SUCCESS;
+ }
+ if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
+ return FAILURE;
+ }
+ zend_hash_move_forward_ex(aht, &intern->pos);
+ spl_array_update_pos(intern);
+ } while (1);
+ }
+ return FAILURE;
+} /* }}} */
+
+static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
+{
+ zend_hash_move_forward_ex(aht, &intern->pos);
+ spl_array_update_pos(intern);
+ if (Z_TYPE_P(intern->array) == IS_OBJECT) {
+ return spl_array_skip_protected(intern, aht TSRMLS_CC);
+ } else {
+ return zend_hash_has_more_elements_ex(aht, &intern->pos);
+ }
+} /* }}} */
+
+static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
+{
+ if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
+ return FAILURE;
+ }
+
+ return spl_array_next_no_verify(intern, aht TSRMLS_CC);
+} /* }}} */
+
+static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
+{
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ return spl_array_next_ex(intern, aht TSRMLS_CC);
+
+} /* }}} */
+
+/* define an overloaded iterator structure */
+typedef struct {
+ zend_user_iterator intern;
+ spl_array_object *object;
+} spl_array_it;
+
+static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ zval_ptr_dtor((zval**)&iterator->intern.it.data);
+
+ efree(iterator);
+}
+/* }}} */
+
+static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+ spl_array_object *object = iterator->object;
+ HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
+ return zend_user_it_valid(iter TSRMLS_CC);
+ } else {
+ if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::valid(): " TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+
+ return zend_hash_has_more_elements_ex(aht, &object->pos);
+ }
+}
+/* }}} */
+
+static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+ spl_array_object *object = iterator->object;
+ HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
+ zend_user_it_get_current_data(iter, data TSRMLS_CC);
+ } else {
+ if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
+ *data = NULL;
+ }
+ }
+}
+/* }}} */
+
+static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+ spl_array_object *object = iterator->object;
+ HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
+ return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
+ } else {
+ if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) {
+ return HASH_KEY_NON_EXISTANT;
+ }
+
+ return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
+ }
+}
+/* }}} */
+
+static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+ spl_array_object *object = iterator->object;
+ HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
+ zend_user_it_move_forward(iter TSRMLS_CC);
+ } else {
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
+ } else {
+ spl_array_next_no_verify(object, aht TSRMLS_CC);
+ }
+ }
+}
+/* }}} */
+
+static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
+{
+
+ zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
+ spl_array_update_pos(intern);
+ spl_array_skip_protected(intern, aht TSRMLS_CC);
+
+} /* }}} */
+
+static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
+{
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ spl_array_rewind_ex(intern, aht TSRMLS_CC);
+}
+/* }}} */
+
+static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator = (spl_array_it *)iter;
+ spl_array_object *object = iterator->object;
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
+ zend_user_it_rewind(iter TSRMLS_CC);
+ } else {
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ spl_array_rewind(object TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ spl_array_set_array */
+static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
+
+ if (Z_TYPE_PP(array) == IS_ARRAY) {
+ SEPARATE_ZVAL_IF_NOT_REF(array);
+ }
+
+ if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
+ zval_ptr_dtor(&intern->array);
+ if (just_array) {
+ spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
+ ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
+ }
+ ar_flags |= SPL_ARRAY_USE_OTHER;
+ intern->array = *array;
+ } else {
+ if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
+ return;
+ }
+ zval_ptr_dtor(&intern->array);
+ intern->array = *array;
+ }
+ if (object == *array) {
+ intern->ar_flags |= SPL_ARRAY_IS_SELF;
+ intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
+ } else {
+ intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
+ }
+ intern->ar_flags |= ar_flags;
+ Z_ADDREF_P(intern->array);
+ if (Z_TYPE_PP(array) == IS_OBJECT) {
+ zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
+ if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
+ || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name);
+ }
+ }
+
+ spl_array_rewind(intern TSRMLS_CC);
+}
+/* }}} */
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_array_it_funcs = {
+ spl_array_it_dtor,
+ spl_array_it_valid,
+ spl_array_it_get_current_data,
+ spl_array_it_get_current_key,
+ spl_array_it_move_forward,
+ spl_array_it_rewind
+};
+
+zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
+{
+ spl_array_it *iterator;
+ spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+
+ iterator = emalloc(sizeof(spl_array_it));
+
+ Z_ADDREF_P(object);
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_array_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
+ iterator->object = array_object;
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
+ proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
+ Constructs a new array iterator from a path. */
+SPL_METHOD(Array, __construct)
+{
+ zval *object = getThis();
+ spl_array_object *intern;
+ zval **array;
+ long ar_flags = 0;
+ zend_class_entry *ce_get_iterator = spl_ce_Iterator;
+ zend_error_handling error_handling;
+
+ if (ZEND_NUM_ARGS() == 0) {
+ return; /* nothing to do */
+ }
+
+ zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
+
+ intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ if (ZEND_NUM_ARGS() > 2) {
+ intern->ce_get_iterator = ce_get_iterator;
+ }
+
+ ar_flags &= ~SPL_ARRAY_INT_MASK;
+
+ spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+
+}
+ /* }}} */
+
+/* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
+ Set the class used in getIterator. */
+SPL_METHOD(Array, setIteratorClass)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ zend_class_entry * ce_get_iterator = spl_ce_Iterator;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
+ return;
+ }
+
+ intern->ce_get_iterator = ce_get_iterator;
+}
+/* }}} */
+
+/* {{{ proto string ArrayObject::getIteratorClass()
+ Get the class used in getIterator. */
+SPL_METHOD(Array, getIteratorClass)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_STRING(intern->ce_get_iterator->name, 1);
+}
+/* }}} */
+
+/* {{{ proto int ArrayObject::getFlags()
+ Get flags */
+SPL_METHOD(Array, getFlags)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
+}
+/* }}} */
+
+/* {{{ proto void ArrayObject::setFlags(int flags)
+ Set flags */
+SPL_METHOD(Array, setFlags)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ long ar_flags = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
+ return;
+ }
+
+ intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
+}
+/* }}} */
+
+/* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
+ Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
+SPL_METHOD(Array, exchangeArray)
+{
+ zval *object = getThis(), *tmp, **array;
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ array_init(return_value);
+ zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
+ return;
+ }
+
+ spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
+
+}
+/* }}} */
+
+/* {{{ proto ArrayIterator ArrayObject::getIterator()
+ Create a new iterator from a ArrayObject instance */
+SPL_METHOD(Array, getIterator)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ spl_array_object *iterator;
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
+ Z_SET_REFCOUNT_P(return_value, 1);
+ Z_SET_ISREF_P(return_value);
+}
+/* }}} */
+
+/* {{{ proto void ArrayIterator::rewind()
+ Rewind array back to the start */
+SPL_METHOD(Array, rewind)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_array_rewind(intern TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void ArrayIterator::seek(int $position)
+ Seek to position. */
+SPL_METHOD(Array, seek)
+{
+ long opos, position;
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ int result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
+ return;
+ }
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ opos = position;
+
+ if (position >= 0) { /* negative values are not supported */
+ spl_array_rewind(intern TSRMLS_CC);
+ result = SUCCESS;
+
+ while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
+
+ if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
+ return; /* ok */
+ }
+ }
+ zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
+} /* }}} */
+
+int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
+{
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ HashPosition pos;
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ *count = 0;
+ return FAILURE;
+ }
+
+ if (Z_TYPE_P(intern->array) == IS_OBJECT) {
+ /* We need to store the 'pos' since we'll modify it in the functions
+ * we're going to call and which do not support 'pos' as parameter. */
+ pos = intern->pos;
+ *count = 0;
+ spl_array_rewind(intern TSRMLS_CC);
+ while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
+ (*count)++;
+ }
+ spl_array_set_pos(intern, pos);
+ return SUCCESS;
+ } else {
+ *count = zend_hash_num_elements(aht);
+ return SUCCESS;
+ }
+} /* }}} */
+
+int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_count) {
+ zval *rv;
+ zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ convert_to_long(intern->retval);
+ *count = (long) Z_LVAL_P(intern->retval);
+ return SUCCESS;
+ }
+ *count = 0;
+ return FAILURE;
+ }
+ return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto int ArrayObject::count()
+ proto int ArrayIterator::count()
+ Return the number of elements in the Iterator. */
+SPL_METHOD(Array, count)
+{
+ long count;
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
+
+ RETURN_LONG(count);
+} /* }}} */
+
+static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ zval *tmp, *arg = NULL;
+ zval *retval_ptr = NULL;
+
+ MAKE_STD_ZVAL(tmp);
+ Z_TYPE_P(tmp) = IS_ARRAY;
+ Z_ARRVAL_P(tmp) = aht;
+
+ if (!use_arg) {
+ aht->nApplyCount++;
+ zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
+ aht->nApplyCount--;
+ } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) {
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|z", &arg) == FAILURE) {
+ Z_TYPE_P(tmp) = IS_NULL;
+ zval_ptr_dtor(&tmp);
+ zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0 TSRMLS_CC);
+ return;
+ }
+ aht->nApplyCount++;
+ zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, arg? 2 : 1, tmp, arg TSRMLS_CC);
+ aht->nApplyCount--;
+ } else {
+ if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
+ Z_TYPE_P(tmp) = IS_NULL;
+ zval_ptr_dtor(&tmp);
+ zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
+ return;
+ }
+ aht->nApplyCount++;
+ zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
+ aht->nApplyCount--;
+ }
+ Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
+ zval_ptr_dtor(&tmp);
+ if (retval_ptr) {
+ COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
+ }
+} /* }}} */
+
+#define SPL_ARRAY_METHOD(cname, fname, use_arg) \
+SPL_METHOD(cname, fname) \
+{ \
+ spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
+}
+
+/* {{{ proto int ArrayObject::asort([int $sort_flags = SORT_REGULAR ])
+ proto int ArrayIterator::asort([int $sort_flags = SORT_REGULAR ])
+ Sort the entries by values. */
+SPL_ARRAY_METHOD(Array, asort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::ksort([int $sort_flags = SORT_REGULAR ])
+ proto int ArrayIterator::ksort([int $sort_flags = SORT_REGULAR ])
+ Sort the entries by key. */
+SPL_ARRAY_METHOD(Array, ksort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::uasort(callback cmp_function)
+ proto int ArrayIterator::uasort(callback cmp_function)
+ Sort the entries by values user defined function. */
+SPL_ARRAY_METHOD(Array, uasort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::uksort(callback cmp_function)
+ proto int ArrayIterator::uksort(callback cmp_function)
+ Sort the entries by key using user defined function. */
+SPL_ARRAY_METHOD(Array, uksort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::natsort()
+ proto int ArrayIterator::natsort()
+ Sort the entries by values using "natural order" algorithm. */
+SPL_ARRAY_METHOD(Array, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::natcasesort()
+ proto int ArrayIterator::natcasesort()
+ Sort the entries by key using case insensitive "natural order" algorithm. */
+SPL_ARRAY_METHOD(Array, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
+
+/* {{{ proto mixed|NULL ArrayIterator::current()
+ Return current array entry */
+SPL_METHOD(Array, current)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ zval **entry;
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
+ return;
+ }
+ RETVAL_ZVAL(*entry, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed|NULL ArrayIterator::key()
+ Return current array key */
+SPL_METHOD(Array, key)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
+} /* }}} */
+
+void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ char *string_key;
+ uint string_length;
+ ulong num_key;
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ return;
+ }
+
+ switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
+ case HASH_KEY_IS_STRING:
+ RETVAL_STRINGL(string_key, string_length - 1, 0);
+ break;
+ case HASH_KEY_IS_LONG:
+ RETVAL_LONG(num_key);
+ break;
+ case HASH_KEY_NON_EXISTANT:
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ proto void ArrayIterator::next()
+ Move to next entry */
+SPL_METHOD(Array, next)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ return;
+ }
+
+ spl_array_next_no_verify(intern, aht TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool ArrayIterator::valid()
+ Check whether array contains more entries */
+SPL_METHOD(Array, valid)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ } else {
+ RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool RecursiveArrayIterator::hasChildren()
+ Check whether current element has children (e.g. is an array) */
+SPL_METHOD(Array, hasChildren)
+{
+ zval *object = getThis(), **entry;
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
+}
+/* }}} */
+
+/* {{{ proto object RecursiveArrayIterator::getChildren()
+ Create a sub iterator for the current element (same class as $this) */
+SPL_METHOD(Array, getChildren)
+{
+ zval *object = getThis(), **entry, *flags;
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
+ return;
+ }
+
+ if (Z_TYPE_PP(entry) == IS_OBJECT) {
+ if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
+ return;
+ }
+ if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
+ RETURN_ZVAL(*entry, 0, 0);
+ }
+ }
+
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
+ spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
+ zval_ptr_dtor(&flags);
+}
+/* }}} */
+
+/* {{{ proto string ArrayObject::serialize()
+ Serialize the object */
+SPL_METHOD(Array, serialize)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ zval members, *pmembers;
+ php_serialize_data_t var_hash;
+ smart_str buf = {0};
+ zval *flags;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
+
+ /* storage */
+ smart_str_appendl(&buf, "x:", 2);
+ php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
+ zval_ptr_dtor(&flags);
+
+ if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
+ php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC);
+ smart_str_appendc(&buf, ';');
+ }
+
+ /* members */
+ smart_str_appendl(&buf, "m:", 2);
+ INIT_PZVAL(&members);
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ Z_ARRVAL(members) = intern->std.properties;
+ Z_TYPE(members) = IS_ARRAY;
+ pmembers = &members;
+ php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
+
+ /* done */
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ if (buf.c) {
+ RETURN_STRINGL(buf.c, buf.len, 0);
+ }
+
+ RETURN_NULL();
+} /* }}} */
+
+/* {{{ proto void ArrayObject::unserialize(string serialized)
+ * unserialize the object
+ */
+SPL_METHOD(Array, unserialize)
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ char *buf;
+ int buf_len;
+ const unsigned char *p, *s;
+ php_unserialize_data_t var_hash;
+ zval *pmembers, *pflags = NULL;
+ long flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+ return;
+ }
+
+ if (buf_len == 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
+ return;
+ }
+
+ /* storage */
+ s = p = (const unsigned char*)buf;
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+
+ if (*p!= 'x' || *++p != ':') {
+ goto outexcept;
+ }
+ ++p;
+
+ ALLOC_INIT_ZVAL(pflags);
+ if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
+ zval_ptr_dtor(&pflags);
+ goto outexcept;
+ }
+
+ --p; /* for ';' */
+ flags = Z_LVAL_P(pflags);
+ zval_ptr_dtor(&pflags);
+ /* flags needs to be verified and we also need to verify whether the next
+ * thing we get is ';'. After that we require an 'm' or somethign else
+ * where 'm' stands for members and anything else should be an array. If
+ * neither 'a' or 'm' follows we have an error. */
+
+ if (*p != ';') {
+ goto outexcept;
+ }
+ ++p;
+
+ if (*p!='m') {
+ if (*p!='a' && *p!='O' && *p!='C') {
+ goto outexcept;
+ }
+ intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
+ intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
+ zval_ptr_dtor(&intern->array);
+ ALLOC_INIT_ZVAL(intern->array);
+ if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ goto outexcept;
+ }
+ }
+ if (*p != ';') {
+ goto outexcept;
+ }
+ ++p;
+
+ /* members */
+ if (*p!= 'm' || *++p != ':') {
+ goto outexcept;
+ }
+ ++p;
+
+ ALLOC_INIT_ZVAL(pmembers);
+ if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&pmembers);
+ goto outexcept;
+ }
+
+ /* copy members */
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
+ zval_ptr_dtor(&pmembers);
+
+ /* done reading $serialized */
+
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ return;
+
+outexcept:
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ return;
+
+} /* }}} */
+
+/* {{{ arginfo and function tbale */
+ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
+ ZEND_ARG_INFO(0, array)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
+ ZEND_ARG_INFO(0, position)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
+ ZEND_ARG_INFO(0, array)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
+ ZEND_ARG_INFO(0, iteratorClass)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
+ ZEND_ARG_INFO(0, cmp_function)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
+ ZEND_ARG_INFO(0, serialized)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_funcs_ArrayObject[] = {
+ SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
+ /* ArrayObject specific */
+ SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getIteratorClass, arginfo_array_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_funcs_ArrayIterator[] = {
+ SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
+ /* ArrayIterator specific */
+ SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, key, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, next, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, valid, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
+ SPL_ME(Array, hasChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION(spl_array) */
+PHP_MINIT_FUNCTION(spl_array)
+{
+ REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
+ REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
+ REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
+ REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
+ REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
+ memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
+ spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
+ spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
+ spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
+ spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
+ spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
+
+ spl_handler_ArrayObject.get_properties = spl_array_get_properties;
+ spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
+ spl_handler_ArrayObject.read_property = spl_array_read_property;
+ spl_handler_ArrayObject.write_property = spl_array_write_property;
+ spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
+ spl_handler_ArrayObject.has_property = spl_array_has_property;
+ spl_handler_ArrayObject.unset_property = spl_array_unset_property;
+
+ spl_handler_ArrayObject.compare_objects = spl_array_compare_objects;
+
+ REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
+ REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
+ REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
+ REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
+ REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
+ REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
+ memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
+ spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
+ spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
+
+ REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
+ REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
+
+ REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
+ REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
+
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h
new file mode 100644
index 0000000..0423d89
--- /dev/null
+++ b/ext/spl/spl_array.h
@@ -0,0 +1,46 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_ARRAY_H
+#define SPL_ARRAY_H
+
+#include "php.h"
+#include "php_spl.h"
+#include "spl_iterators.h"
+
+extern PHPAPI zend_class_entry *spl_ce_ArrayObject;
+extern PHPAPI zend_class_entry *spl_ce_ArrayIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
+
+PHP_MINIT_FUNCTION(spl_array);
+
+extern void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC);
+extern void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC);
+
+#endif /* SPL_ARRAY_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
new file mode 100644
index 0000000..f43a370
--- /dev/null
+++ b/ext/spl/spl_directory.c
@@ -0,0 +1,3068 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/file.h"
+#include "ext/standard/php_string.h"
+#include "zend_compile.h"
+#include "zend_exceptions.h"
+#include "zend_interfaces.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+#include "spl_directory.h"
+#include "spl_exceptions.h"
+
+#include "php.h"
+#include "fopen_wrappers.h"
+
+#include "ext/standard/basic_functions.h"
+#include "ext/standard/php_filestat.h"
+
+#define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
+
+/* declare the class handlers */
+static zend_object_handlers spl_filesystem_object_handlers;
+/* includes handler to validate object state when retrieving methods */
+static zend_object_handlers spl_filesystem_object_check_handlers;
+
+/* decalre the class entry */
+PHPAPI zend_class_entry *spl_ce_SplFileInfo;
+PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
+PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
+PHPAPI zend_class_entry *spl_ce_GlobIterator;
+PHPAPI zend_class_entry *spl_ce_SplFileObject;
+PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
+
+static void spl_filesystem_file_free_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (intern->u.file.current_line) {
+ efree(intern->u.file.current_line);
+ intern->u.file.current_line = NULL;
+ }
+ if (intern->u.file.current_zval) {
+ zval_ptr_dtor(&intern->u.file.current_zval);
+ intern->u.file.current_zval = NULL;
+ }
+} /* }}} */
+
+static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)object;
+
+ if (intern->oth_handler && intern->oth_handler->dtor) {
+ intern->oth_handler->dtor(intern TSRMLS_CC);
+ }
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+
+ if (intern->_path) {
+ efree(intern->_path);
+ }
+ if (intern->file_name) {
+ efree(intern->file_name);
+ }
+ switch(intern->type) {
+ case SPL_FS_INFO:
+ break;
+ case SPL_FS_DIR:
+ if (intern->u.dir.dirp) {
+ php_stream_close(intern->u.dir.dirp);
+ intern->u.dir.dirp = NULL;
+ }
+ if (intern->u.dir.sub_path) {
+ efree(intern->u.dir.sub_path);
+ }
+ break;
+ case SPL_FS_FILE:
+ if (intern->u.file.stream) {
+ if (intern->u.file.zcontext) {
+/* zend_list_delref(Z_RESVAL_P(intern->zcontext));*/
+ }
+ if (!intern->u.file.stream->is_persistent) {
+ php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE);
+ } else {
+ php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE_PERSISTENT);
+ }
+ if (intern->u.file.open_mode) {
+ efree(intern->u.file.open_mode);
+ }
+ if (intern->orig_path) {
+ efree(intern->orig_path);
+ }
+ }
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ break;
+ }
+
+ {
+ zend_object_iterator *iterator;
+ iterator = (zend_object_iterator*)
+ spl_filesystem_object_to_iterator(intern);
+ if (iterator->data != NULL) {
+ iterator->data = NULL;
+ iterator->funcs->dtor(iterator TSRMLS_CC);
+ }
+ }
+ efree(object);
+} /* }}} */
+
+/* {{{ spl_ce_dir_object_new */
+/* creates the object by
+ - allocating memory
+ - initializing the object members
+ - storing the object
+ - setting it's handlers
+
+ called from
+ - clone
+ - new
+ */
+static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_type, spl_filesystem_object **obj TSRMLS_DC)
+{
+ zend_object_value retval;
+ spl_filesystem_object *intern;
+
+ intern = emalloc(sizeof(spl_filesystem_object));
+ memset(intern, 0, sizeof(spl_filesystem_object));
+ /* 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;
+
+ 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;
+ return retval;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_object_new */
+/* 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);
+}
+/* }}} */
+
+/* {{{ spl_filesystem_object_new_ex */
+static zend_object_value spl_filesystem_object_new_check(zend_class_entry *class_type TSRMLS_DC)
+{
+ zend_object_value ret = spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC);
+ ret.handlers = &spl_filesystem_object_check_handlers;
+ return ret;
+}
+/* }}} */
+
+
+PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC) /* {{{ */
+{
+#ifdef HAVE_GLOB
+ if (intern->type == SPL_FS_DIR) {
+ if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
+ return php_glob_stream_get_path(intern->u.dir.dirp, 0, len);
+ }
+ }
+#endif
+ if (len) {
+ *len = intern->_path_len;
+ }
+ return intern->_path;
+} /* }}} */
+
+static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
+
+ if (!intern->file_name) {
+ switch (intern->type) {
+ case SPL_FS_INFO:
+ case SPL_FS_FILE:
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Object not initialized");
+ break;
+ case SPL_FS_DIR:
+ intern->file_name_len = spprintf(&intern->file_name, 0, "%s%c%s",
+ spl_filesystem_object_get_path(intern, NULL TSRMLS_CC),
+ slash, intern->u.dir.entry.d_name);
+ break;
+ }
+ }
+} /* }}} */
+
+static int spl_filesystem_dir_read(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
+ intern->u.dir.entry.d_name[0] = '\0';
+ return 0;
+ } else {
+ return 1;
+ }
+}
+/* }}} */
+
+#define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
+
+static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
+{
+ return !strcmp(d_name, ".") || !strcmp(d_name, "..");
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_open */
+/* open a directory resource */
+static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path TSRMLS_DC)
+{
+ int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
+
+ intern->type = SPL_FS_DIR;
+ intern->_path_len = strlen(path);
+ intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context));
+
+ if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
+ intern->_path = estrndup(path, --intern->_path_len);
+ } else {
+ intern->_path = estrndup(path, intern->_path_len);
+ }
+ intern->u.dir.index = 0;
+
+ if (EG(exception) || intern->u.dir.dirp == NULL) {
+ intern->u.dir.entry.d_name[0] = '\0';
+ if (!EG(exception)) {
+ /* open failed w/out notice (turned to exception due to EH_THROW) */
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0
+ TSRMLS_CC, "Failed to open directory \"%s\"", path);
+ }
+ } else {
+ do {
+ spl_filesystem_dir_read(intern TSRMLS_CC);
+ } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
+ }
+}
+/* }}} */
+
+static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_include_path, int silent TSRMLS_DC) /* {{{ */
+{
+ zval tmp;
+
+ intern->type = SPL_FS_FILE;
+
+ php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, &tmp TSRMLS_CC);
+ if (Z_LVAL(tmp)) {
+ intern->u.file.open_mode = NULL;
+ intern->file_name = NULL;
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Cannot use SplFileObject with directories");
+ return FAILURE;
+ }
+
+ intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
+ intern->u.file.stream = php_stream_open_wrapper_ex(intern->file_name, intern->u.file.open_mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, intern->u.file.context);
+
+ if (!intern->file_name_len || !intern->u.file.stream) {
+ if (!EG(exception)) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot open file '%s'", intern->file_name_len ? intern->file_name : "");
+ }
+ intern->file_name = NULL; /* until here it is not a copy */
+ intern->u.file.open_mode = NULL;
+ return FAILURE;
+ }
+
+ if (intern->u.file.zcontext) {
+ zend_list_addref(Z_RESVAL_P(intern->u.file.zcontext));
+ }
+
+ if (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
+ intern->file_name_len--;
+ }
+
+ intern->orig_path = estrndup(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path));
+
+ intern->file_name = estrndup(intern->file_name, intern->file_name_len);
+ intern->u.file.open_mode = estrndup(intern->u.file.open_mode, intern->u.file.open_mode_len);
+
+ /* avoid reference counting in debug mode, thus do it manually */
+ ZVAL_RESOURCE(&intern->u.file.zresource, php_stream_get_resource_id(intern->u.file.stream));
+ Z_SET_REFCOUNT(intern->u.file.zresource, 1);
+
+ intern->u.file.delimiter = ',';
+ intern->u.file.enclosure = '"';
+ intern->u.file.escape = '\\';
+
+ zend_hash_find(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline"), (void **) &intern->u.file.func_getCurr);
+
+ return SUCCESS;
+} /* }}} */
+
+/* {{{ spl_filesystem_object_clone */
+/* Local zend_object_value creation (on stack)
+ Load the 'other' object
+ Create a new empty object (See spl_filesystem_object_new_ex)
+ Open the directory
+ Clone other members (properties)
+ */
+static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_filesystem_object *intern;
+ spl_filesystem_object *source;
+ int index, skip_dots;
+
+ 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_object = &intern->std;
+
+ intern->flags = source->flags;
+
+ switch (source->type) {
+ case SPL_FS_INFO:
+ intern->_path_len = source->_path_len;
+ intern->_path = estrndup(source->_path, source->_path_len);
+ intern->file_name_len = source->file_name_len;
+ intern->file_name = estrndup(source->file_name, intern->file_name_len);
+ break;
+ case SPL_FS_DIR:
+ spl_filesystem_dir_open(intern, source->_path TSRMLS_CC);
+ /* read until we hit the position in which we were before */
+ skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS);
+ for(index = 0; index < source->u.dir.index; ++index) {
+ do {
+ spl_filesystem_dir_read(intern TSRMLS_CC);
+ } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
+ }
+ intern->u.dir.index = index;
+ break;
+ case SPL_FS_FILE:
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "An object of class %s cannot be cloned", old_object->ce->name);
+ break;
+ }
+
+ intern->file_class = source->file_class;
+ intern->info_class = source->info_class;
+ intern->oth = source->oth;
+ intern->oth_handler = source->oth_handler;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ if (intern->oth_handler && intern->oth_handler->clone) {
+ intern->oth_handler->clone(source, intern TSRMLS_CC);
+ }
+
+ return new_obj_val;
+}
+/* }}} */
+
+void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path, int len, int use_copy TSRMLS_DC) /* {{{ */
+{
+ char *p1, *p2;
+
+ if (intern->file_name) {
+ efree(intern->file_name);
+ }
+
+ intern->file_name = use_copy ? estrndup(path, len) : path;
+ intern->file_name_len = len;
+
+ while(IS_SLASH_AT(intern->file_name, intern->file_name_len-1) && intern->file_name_len > 1) {
+ intern->file_name[intern->file_name_len-1] = 0;
+ intern->file_name_len--;
+ }
+
+ p1 = strrchr(intern->file_name, '/');
+#if defined(PHP_WIN32) || defined(NETWARE)
+ p2 = strrchr(intern->file_name, '\\');
+#else
+ p2 = 0;
+#endif
+ if (p1 || p2) {
+ intern->_path_len = (p1 > p2 ? p1 : p2) - intern->file_name;
+ } else {
+ intern->_path_len = 0;
+ }
+
+ if (intern->_path) {
+ efree(intern->_path);
+ }
+ intern->_path = estrndup(path, intern->_path_len);
+} /* }}} */
+
+static spl_filesystem_object * spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, int file_path_len, int use_copy, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ spl_filesystem_object *intern;
+ zval *arg1;
+ zend_error_handling error_handling;
+
+ if (!file_path || !file_path_len) {
+#if defined(PHP_WIN32)
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot create SplFileInfo for empty path");
+ if (file_path && !use_copy) {
+ efree(file_path);
+ }
+#else
+ if (file_path && !use_copy) {
+ efree(file_path);
+ }
+ file_path_len = 1;
+ file_path = "/";
+#endif
+ return NULL;
+ }
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ ce = ce ? ce : source->info_class;
+
+ zend_update_class_constants(ce TSRMLS_CC);
+
+ return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+ Z_TYPE_P(return_value) = IS_OBJECT;
+
+ if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
+ MAKE_STD_ZVAL(arg1);
+ ZVAL_STRINGL(arg1, file_path, file_path_len, use_copy);
+ zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1);
+ zval_ptr_dtor(&arg1);
+ } else {
+ spl_filesystem_info_set_filename(intern, file_path, file_path_len, use_copy TSRMLS_CC);
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return intern;
+} /* }}} */
+
+static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ spl_filesystem_object *intern;
+ zend_bool use_include_path = 0;
+ zval *arg1, *arg2;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ switch (source->type) {
+ case SPL_FS_INFO:
+ case SPL_FS_FILE:
+ break;
+ case SPL_FS_DIR:
+ if (!source->u.dir.entry.d_name[0]) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Could not open file");
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ }
+
+ switch (type) {
+ case SPL_FS_INFO:
+ ce = ce ? ce : source->info_class;
+
+ zend_update_class_constants(ce TSRMLS_CC);
+
+ return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+ Z_TYPE_P(return_value) = IS_OBJECT;
+
+ spl_filesystem_object_get_file_name(source TSRMLS_CC);
+ if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
+ MAKE_STD_ZVAL(arg1);
+ ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1);
+ zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1);
+ zval_ptr_dtor(&arg1);
+ } else {
+ intern->file_name = estrndup(source->file_name, source->file_name_len);
+ intern->file_name_len = source->file_name_len;
+ intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC);
+ intern->_path = estrndup(intern->_path, intern->_path_len);
+ }
+ break;
+ case SPL_FS_FILE:
+ ce = ce ? ce : source->file_class;
+
+ zend_update_class_constants(ce TSRMLS_CC);
+
+ return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
+ Z_TYPE_P(return_value) = IS_OBJECT;
+
+ spl_filesystem_object_get_file_name(source TSRMLS_CC);
+
+ if (ce->constructor->common.scope != spl_ce_SplFileObject) {
+ MAKE_STD_ZVAL(arg1);
+ MAKE_STD_ZVAL(arg2);
+ ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1);
+ ZVAL_STRINGL(arg2, "r", 1, 1);
+ zend_call_method_with_2_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1, arg2);
+ zval_ptr_dtor(&arg1);
+ zval_ptr_dtor(&arg2);
+ } else {
+ intern->file_name = source->file_name;
+ intern->file_name_len = source->file_name_len;
+ intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC);
+ intern->_path = estrndup(intern->_path, intern->_path_len);
+
+ intern->u.file.open_mode = "r";
+ intern->u.file.open_mode_len = 1;
+
+ if (ht && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sbr",
+ &intern->u.file.open_mode, &intern->u.file.open_mode_len,
+ &use_include_path, &intern->u.file.zcontext) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ intern->u.file.open_mode = NULL;
+ intern->file_name = NULL;
+ zval_dtor(return_value);
+ Z_TYPE_P(return_value) = IS_NULL;
+ return NULL;
+ }
+
+ if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ zval_dtor(return_value);
+ Z_TYPE_P(return_value) = IS_NULL;
+ return NULL;
+ }
+ }
+ break;
+ case SPL_FS_DIR:
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Operation not supported");
+ return NULL;
+ }
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+} /* }}} */
+
+static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
+{
+ return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
+}
+/* }}} */
+
+static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, int *len TSRMLS_DC) { /* {{{ */
+ switch (intern->type) {
+ case SPL_FS_INFO:
+ case SPL_FS_FILE:
+ *len = intern->file_name_len;
+ return intern->file_name;
+ case SPL_FS_DIR:
+ if (intern->u.dir.entry.d_name[0]) {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ *len = intern->file_name_len;
+ return intern->file_name;
+ }
+ }
+ *len = 0;
+ return NULL;
+}
+/* }}} */
+
+static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ HashTable *rv;
+ zval *tmp, zrv;
+ char *pnstr, *path;
+ int pnlen, path_len;
+ char stmp[2];
+
+ *is_temp = 1;
+
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+
+ ALLOC_HASHTABLE(rv);
+ ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 3, 0);
+
+ INIT_PZVAL(&zrv);
+ Z_ARRVAL(zrv) = rv;
+
+ zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1, &pnlen TSRMLS_CC);
+ path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, path, path_len, 1);
+ efree(pnstr);
+
+ if (intern->file_name) {
+ pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1, &pnlen TSRMLS_CC);
+ spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
+
+ if (path_len && path_len < intern->file_name_len) {
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1);
+ } else {
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name, intern->file_name_len, 1);
+ }
+ efree(pnstr);
+ }
+ if (intern->type == SPL_FS_DIR) {
+#ifdef HAVE_GLOB
+ pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1, &pnlen TSRMLS_CC);
+ if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->_path, intern->_path_len, 1);
+ } else {
+ add_assoc_bool_ex(&zrv, pnstr, pnlen+1, 0);
+ }
+ efree(pnstr);
+#endif
+ pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1, &pnlen TSRMLS_CC);
+ if (intern->u.dir.sub_path) {
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1);
+ } else {
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, "", 0, 1);
+ }
+ efree(pnstr);
+ }
+ if (intern->type == SPL_FS_FILE) {
+ pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1, &pnlen TSRMLS_CC);
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.file.open_mode, intern->u.file.open_mode_len, 1);
+ efree(pnstr);
+ stmp[1] = '\0';
+ stmp[0] = intern->u.file.delimiter;
+ pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1, &pnlen TSRMLS_CC);
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1);
+ efree(pnstr);
+ stmp[0] = intern->u.file.enclosure;
+ pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1, &pnlen TSRMLS_CC);
+ add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1);
+ efree(pnstr);
+ }
+
+ return rv;
+}
+/* }}} */
+
+zend_function *spl_filesystem_object_get_method_check(zval **object_ptr, char *method, int method_len, const struct _zend_literal *key TSRMLS_DC) /* {{{ */
+{
+ spl_filesystem_object *fsobj = zend_object_store_get_object(*object_ptr TSRMLS_CC);
+
+ if (fsobj->u.dir.entry.d_name[0] == '\0' && fsobj->orig_path == NULL) {
+ method = "_bad_state_ex";
+ method_len = sizeof("_bad_state_ex") - 1;
+ key = NULL;
+ }
+
+ return zend_get_std_object_handlers()->get_method(object_ptr, method, method_len, key TSRMLS_CC);
+}
+/* }}} */
+
+#define DIT_CTOR_FLAGS 0x00000001
+#define DIT_CTOR_GLOB 0x00000002
+
+void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, long ctor_flags) /* {{{ */
+{
+ spl_filesystem_object *intern;
+ char *path;
+ int parsed, len;
+ long flags;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+
+ if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
+ flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
+ parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &len, &flags);
+ } else {
+ flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
+ parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len);
+ }
+ if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) {
+ flags |= SPL_FILE_DIR_SKIPDOTS;
+ }
+ if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) {
+ flags |= SPL_FILE_DIR_UNIXPATHS;
+ }
+ if (parsed == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+ if (!len) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Directory name must not be empty.");
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ intern->flags = flags;
+#ifdef HAVE_GLOB
+ if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && strstr(path, "glob://") != path) {
+ spprintf(&path, 0, "glob://%s", path);
+ spl_filesystem_dir_open(intern, path TSRMLS_CC);
+ efree(path);
+ } else
+#endif
+ {
+ spl_filesystem_dir_open(intern, path TSRMLS_CC);
+
+ }
+
+ intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator TSRMLS_CC) ? 1 : 0;
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void DirectoryIterator::__construct(string path)
+ Cronstructs a new dir iterator from a path. */
+SPL_METHOD(DirectoryIterator, __construct)
+{
+ spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
+
+/* {{{ proto void DirectoryIterator::rewind()
+ Rewind dir back to the start */
+SPL_METHOD(DirectoryIterator, rewind)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern->u.dir.index = 0;
+ if (intern->u.dir.dirp) {
+ php_stream_rewinddir(intern->u.dir.dirp);
+ }
+ spl_filesystem_dir_read(intern TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto string DirectoryIterator::key()
+ Return current dir entry */
+SPL_METHOD(DirectoryIterator, key)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (intern->u.dir.dirp) {
+ RETURN_LONG(intern->u.dir.index);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto DirectoryIterator DirectoryIterator::current()
+ Return this (needed for Iterator interface) */
+SPL_METHOD(DirectoryIterator, current)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ RETURN_ZVAL(getThis(), 1, 0);
+}
+/* }}} */
+
+/* {{{ proto void DirectoryIterator::next()
+ Move to next entry */
+SPL_METHOD(DirectoryIterator, next)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern->u.dir.index++;
+ do {
+ spl_filesystem_dir_read(intern TSRMLS_CC);
+ } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
+ if (intern->file_name) {
+ efree(intern->file_name);
+ intern->file_name = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ proto void DirectoryIterator::seek(int position)
+ Seek to the given position */
+SPL_METHOD(DirectoryIterator, seek)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *retval = NULL;
+ long pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
+ return;
+ }
+
+ if (intern->u.dir.index > pos) {
+ /* we first rewind */
+ zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_rewind, "rewind", &retval);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ }
+
+ while (intern->u.dir.index < pos) {
+ int valid = 0;
+ zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_valid, "valid", &retval);
+ if (retval) {
+ valid = zend_is_true(retval);
+ zval_ptr_dtor(&retval);
+ }
+ if (!valid) {
+ break;
+ }
+ zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_next, "next", &retval);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ }
+} /* }}} */
+
+/* {{{ proto string DirectoryIterator::valid()
+ Check whether dir contains more entries */
+SPL_METHOD(DirectoryIterator, valid)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
+}
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getPath()
+ Return the path */
+SPL_METHOD(SplFileInfo, getPath)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *path;
+ int path_len;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ path = spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
+ RETURN_STRINGL(path, path_len, 1);
+}
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getFilename()
+ Return filename only */
+SPL_METHOD(SplFileInfo, getFilename)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ int path_len;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
+
+ if (path_len && path_len < intern->file_name_len) {
+ RETURN_STRINGL(intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1);
+ } else {
+ RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto string DirectoryIterator::getFilename()
+ Return filename of current dir entry */
+SPL_METHOD(DirectoryIterator, getFilename)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_STRING(intern->u.dir.entry.d_name, 1);
+}
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getExtension()
+ Returns file extension component of path */
+SPL_METHOD(SplFileInfo, getExtension)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *fname = NULL;
+ const char *p;
+ size_t flen;
+ int path_len, idx;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
+
+ if (path_len && path_len < intern->file_name_len) {
+ fname = intern->file_name + path_len + 1;
+ flen = intern->file_name_len - (path_len + 1);
+ } else {
+ fname = intern->file_name;
+ flen = intern->file_name_len;
+ }
+
+ php_basename(fname, flen, NULL, 0, &fname, &flen TSRMLS_CC);
+
+ p = zend_memrchr(fname, '.', flen);
+ if (p) {
+ idx = p - fname;
+ RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1);
+ efree(fname);
+ return;
+ } else {
+ if (fname) {
+ efree(fname);
+ }
+ RETURN_EMPTY_STRING();
+ }
+}
+/* }}}*/
+
+/* {{{ proto string DirectoryIterator::getExtension()
+ Returns the file extension component of path */
+SPL_METHOD(DirectoryIterator, getExtension)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *fname = NULL;
+ const char *p;
+ size_t flen;
+ int idx;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0, &fname, &flen TSRMLS_CC);
+
+ p = zend_memrchr(fname, '.', flen);
+ if (p) {
+ idx = p - fname;
+ RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1);
+ efree(fname);
+ return;
+ } else {
+ if (fname) {
+ efree(fname);
+ }
+ RETURN_EMPTY_STRING();
+ }
+}
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getBasename([string $suffix]) U
+ Returns filename component of path */
+SPL_METHOD(SplFileInfo, getBasename)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *fname, *suffix = 0;
+ size_t flen;
+ int slen = 0, path_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
+
+ if (path_len && path_len < intern->file_name_len) {
+ fname = intern->file_name + path_len + 1;
+ flen = intern->file_name_len - (path_len + 1);
+ } else {
+ fname = intern->file_name;
+ flen = intern->file_name_len;
+ }
+
+ php_basename(fname, flen, suffix, slen, &fname, &flen TSRMLS_CC);
+
+ RETURN_STRINGL(fname, flen, 0);
+}
+/* }}}*/
+
+/* {{{ proto string DirectoryIterator::getBasename([string $suffix]) U
+ Returns filename component of current dir entry */
+SPL_METHOD(DirectoryIterator, getBasename)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *suffix = 0, *fname;
+ int slen = 0;
+ size_t flen;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) {
+ return;
+ }
+
+ php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen, &fname, &flen TSRMLS_CC);
+
+ RETURN_STRINGL(fname, flen, 0);
+}
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getPathname()
+ Return path and filename */
+SPL_METHOD(SplFileInfo, getPathname)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *path;
+ int path_len;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
+ if (path != NULL) {
+ RETURN_STRINGL(path, path_len, 1);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string FilesystemIterator::key()
+ Return getPathname() or getFilename() depending on flags */
+SPL_METHOD(FilesystemIterator, key)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
+ RETURN_STRING(intern->u.dir.entry.d_name, 1);
+ } else {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto string FilesystemIterator::current()
+ Return getFilename(), getFileInfo() or $this depending on flags */
+SPL_METHOD(FilesystemIterator, current)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
+ } else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value TSRMLS_CC);
+ } else {
+ RETURN_ZVAL(getThis(), 1, 0);
+ /*RETURN_STRING(intern->u.dir.entry.d_name, 1);*/
+ }
+}
+/* }}} */
+
+/* {{{ proto bool DirectoryIterator::isDot()
+ Returns true if current entry is '.' or '..' */
+SPL_METHOD(DirectoryIterator, isDot)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
+}
+/* }}} */
+
+/* {{{ proto void SplFileInfo::__construct(string file_name)
+ Cronstructs a new SplFileInfo from a path. */
+/* zend_replace_error_handling() is used to throw exceptions in case
+ the constructor fails. Here we use this to ensure the object
+ has a valid directory resource.
+
+ When the constructor gets called the object is already created
+ by the engine, so we must only call 'additional' initializations.
+ */
+SPL_METHOD(SplFileInfo, __construct)
+{
+ spl_filesystem_object *intern;
+ char *path;
+ int len;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_filesystem_info_set_filename(intern, path, len, 1 TSRMLS_CC);
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+
+ /* intern->type = SPL_FS_INFO; already set */
+}
+/* }}} */
+
+/* {{{ FileInfoFunction */
+#define FileInfoFunction(func_name, func_num) \
+SPL_METHOD(SplFileInfo, func_name) \
+{ \
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+ zend_error_handling error_handling; \
+ if (zend_parse_parameters_none() == FAILURE) { \
+ return; \
+ } \
+ \
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);\
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC); \
+ php_stat(intern->file_name, intern->file_name_len, func_num, return_value TSRMLS_CC); \
+ zend_restore_error_handling(&error_handling TSRMLS_CC); \
+}
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getPerms()
+ Get file permissions */
+FileInfoFunction(getPerms, FS_PERMS)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getInode()
+ Get file inode */
+FileInfoFunction(getInode, FS_INODE)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getSize()
+ Get file size */
+FileInfoFunction(getSize, FS_SIZE)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getOwner()
+ Get file owner */
+FileInfoFunction(getOwner, FS_OWNER)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getGroup()
+ Get file group */
+FileInfoFunction(getGroup, FS_GROUP)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getATime()
+ Get last access time of file */
+FileInfoFunction(getATime, FS_ATIME)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getMTime()
+ Get last modification time of file */
+FileInfoFunction(getMTime, FS_MTIME)
+/* }}} */
+
+/* {{{ proto int SplFileInfo::getCTime()
+ Get inode modification time of file */
+FileInfoFunction(getCTime, FS_CTIME)
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getType()
+ Get file type */
+FileInfoFunction(getType, FS_TYPE)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isWritable()
+ Returns true if file can be written */
+FileInfoFunction(isWritable, FS_IS_W)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isReadable()
+ Returns true if file can be read */
+FileInfoFunction(isReadable, FS_IS_R)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isExecutable()
+ Returns true if file is executable */
+FileInfoFunction(isExecutable, FS_IS_X)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isFile()
+ Returns true if file is a regular file */
+FileInfoFunction(isFile, FS_IS_FILE)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isDir()
+ Returns true if file is directory */
+FileInfoFunction(isDir, FS_IS_DIR)
+/* }}} */
+
+/* {{{ proto bool SplFileInfo::isLink()
+ Returns true if file is symbolic link */
+FileInfoFunction(isLink, FS_IS_LINK)
+/* }}} */
+
+/* {{{ proto string SplFileInfo::getLinkTarget() U
+ Return the target of a symbolic link */
+SPL_METHOD(SplFileInfo, getLinkTarget)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ int ret;
+ char buff[MAXPATHLEN];
+ zend_error_handling error_handling;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+#if defined(PHP_WIN32) || HAVE_SYMLINK
+ if (intern->file_name == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty filename");
+ RETURN_FALSE;
+ } else if (!IS_ABSOLUTE_PATH(intern->file_name, intern->file_name_len)) {
+ char expanded_path[MAXPATHLEN];
+ if (!expand_filepath_with_mode(intern->file_name, expanded_path, NULL, 0, CWD_EXPAND TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
+ RETURN_FALSE;
+ }
+ ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
+ } else {
+ ret = php_sys_readlink(intern->file_name, buff, MAXPATHLEN-1);
+ }
+#else
+ ret = -1; /* always fail if not implemented */
+#endif
+
+ if (ret == -1) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Unable to read link %s, error: %s", intern->file_name, strerror(errno));
+ RETVAL_FALSE;
+ } else {
+ /* Append NULL to the end of the string */
+ buff[ret] = '\0';
+
+ RETVAL_STRINGL(buff, ret, 1);
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+#if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS)
+/* {{{ proto string SplFileInfo::getRealPath()
+ Return the resolved path */
+SPL_METHOD(SplFileInfo, getRealPath)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char buff[MAXPATHLEN];
+ char *filename;
+ zend_error_handling error_handling;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ }
+
+ if (intern->orig_path) {
+ filename = intern->orig_path;
+ } else {
+ filename = intern->file_name;
+ }
+
+
+ if (filename && VCWD_REALPATH(filename, buff)) {
+#ifdef ZTS
+ if (VCWD_ACCESS(buff, F_OK)) {
+ RETVAL_FALSE;
+ } else
+#endif
+ RETVAL_STRING(buff, 1);
+ } else {
+ RETVAL_FALSE;
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+#endif
+
+/* {{{ proto SplFileObject SplFileInfo::openFile([string mode = 'r' [, bool use_include_path [, resource context]]])
+ Open the current file */
+SPL_METHOD(SplFileInfo, openFile)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_filesystem_object_create_type(ht, intern, SPL_FS_FILE, NULL, return_value TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void SplFileInfo::setFileClass([string class_name])
+ Class to use in openFile() */
+SPL_METHOD(SplFileInfo, setFileClass)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = spl_ce_SplFileObject;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
+ intern->file_class = ce;
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void SplFileInfo::setInfoClass([string class_name])
+ Class to use in getFileInfo(), getPathInfo() */
+SPL_METHOD(SplFileInfo, setInfoClass)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = spl_ce_SplFileInfo;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
+ intern->info_class = ce;
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto SplFileInfo SplFileInfo::getFileInfo([string $class_name])
+ Get/copy file info */
+SPL_METHOD(SplFileInfo, getFileInfo)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = intern->info_class;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
+ spl_filesystem_object_create_type(ht, intern, SPL_FS_INFO, ce, return_value TSRMLS_CC);
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto SplFileInfo SplFileInfo::getPathInfo([string $class_name])
+ Get/copy file info */
+SPL_METHOD(SplFileInfo, getPathInfo)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = intern->info_class;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
+ int path_len;
+ char *path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
+ if (path) {
+ char *dpath = estrndup(path, path_len);
+ path_len = php_dirname(dpath, path_len);
+ spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value TSRMLS_CC);
+ efree(dpath);
+ }
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ */
+SPL_METHOD(SplFileInfo, _bad_state_ex)
+{
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC,
+ "The parent constructor was not called: the object is in an "
+ "invalid state ");
+}
+/* }}} */
+
+/* {{{ proto void FilesystemIterator::__construct(string path [, int flags])
+ Cronstructs a new dir iterator from a path. */
+SPL_METHOD(FilesystemIterator, __construct)
+{
+ spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
+}
+/* }}} */
+
+/* {{{ proto void FilesystemIterator::rewind()
+ Rewind dir back to the start */
+SPL_METHOD(FilesystemIterator, rewind)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern->u.dir.index = 0;
+ if (intern->u.dir.dirp) {
+ php_stream_rewinddir(intern->u.dir.dirp);
+ }
+ do {
+ spl_filesystem_dir_read(intern TSRMLS_CC);
+ } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
+}
+/* }}} */
+
+/* {{{ proto int FilesystemIterator::getFlags()
+ Get handling flags */
+SPL_METHOD(FilesystemIterator, getFlags)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
+} /* }}} */
+
+/* {{{ proto void FilesystemIterator::setFlags(long $flags)
+ Set handling flags */
+SPL_METHOD(FilesystemIterator, setFlags)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
+ return;
+ }
+
+ intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
+ intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
+} /* }}} */
+
+/* {{{ proto bool RecursiveDirectoryIterator::hasChildren([bool $allow_links = false])
+ Returns whether current entry is a directory and not '.' or '..' */
+SPL_METHOD(RecursiveDirectoryIterator, hasChildren)
+{
+ zend_bool allow_links = 0;
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &allow_links) == FAILURE) {
+ return;
+ }
+ if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
+ RETURN_FALSE;
+ } else {
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+ if (!allow_links && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
+ php_stat(intern->file_name, intern->file_name_len, FS_IS_LINK, return_value TSRMLS_CC);
+ if (zend_is_true(return_value)) {
+ RETURN_FALSE;
+ }
+ }
+ php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, return_value TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto RecursiveDirectoryIterator DirectoryIterator::getChildren()
+ Returns an iterator for the current entry if it is a directory */
+SPL_METHOD(RecursiveDirectoryIterator, getChildren)
+{
+ zval zpath, zflags;
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_filesystem_object *subdir;
+ char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_object_get_file_name(intern TSRMLS_CC);
+
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
+ RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
+ } else {
+ INIT_PZVAL(&zflags);
+ INIT_PZVAL(&zpath);
+ ZVAL_LONG(&zflags, intern->flags);
+ ZVAL_STRINGL(&zpath, intern->file_name, intern->file_name_len, 0);
+ spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, &zpath, &zflags TSRMLS_CC);
+
+ subdir = (spl_filesystem_object*)zend_object_store_get_object(return_value TSRMLS_CC);
+ if (subdir) {
+ if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
+ subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
+ } else {
+ subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
+ subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
+ }
+ subdir->info_class = intern->info_class;
+ subdir->file_class = intern->file_class;
+ subdir->oth = intern->oth;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto void RecursiveDirectoryIterator::getSubPath()
+ Get sub path */
+SPL_METHOD(RecursiveDirectoryIterator, getSubPath)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (intern->u.dir.sub_path) {
+ RETURN_STRINGL(intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1);
+ } else {
+ RETURN_STRINGL("", 0, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto void RecursiveDirectoryIterator::getSubPathname()
+ Get sub path and file name */
+SPL_METHOD(RecursiveDirectoryIterator, getSubPathname)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *sub_name;
+ int len;
+ char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (intern->u.dir.sub_path) {
+ len = spprintf(&sub_name, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
+ RETURN_STRINGL(sub_name, len, 0);
+ } else {
+ RETURN_STRING(intern->u.dir.entry.d_name, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto int RecursiveDirectoryIterator::__construct(string path [, int flags])
+ Cronstructs a new dir iterator from a path. */
+SPL_METHOD(RecursiveDirectoryIterator, __construct)
+{
+ spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
+}
+/* }}} */
+
+#ifdef HAVE_GLOB
+/* {{{ proto int GlobIterator::__construct(string path [, int flags])
+ Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
+SPL_METHOD(GlobIterator, __construct)
+{
+ spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
+}
+/* }}} */
+
+/* {{{ proto int GlobIterator::cont()
+ Return the number of directories and files found by globbing */
+SPL_METHOD(GlobIterator, count)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
+ RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
+ } else {
+ /* should not happen */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "GlobIterator lost glob state");
+ }
+}
+/* }}} */
+#endif /* HAVE_GLOB */
+
+/* {{{ forward declarations to the iterator handlers */
+static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC);
+static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC);
+static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
+static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC);
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
+ spl_filesystem_dir_it_dtor,
+ spl_filesystem_dir_it_valid,
+ spl_filesystem_dir_it_current_data,
+ spl_filesystem_dir_it_current_key,
+ spl_filesystem_dir_it_move_forward,
+ spl_filesystem_dir_it_rewind
+};
+/* }}} */
+
+/* {{{ spl_ce_dir_get_iterator */
+zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator;
+ spl_filesystem_object *dir_object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
+ iterator = spl_filesystem_object_to_iterator(dir_object);
+
+ /* initialize iterator if it wasn't gotten before */
+ if (iterator->intern.data == NULL) {
+ iterator->intern.data = object;
+ iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
+ /* ->current must be initialized; rewind doesn't set it and valid
+ * doesn't check whether it's set */
+ iterator->current = object;
+ }
+ zval_add_ref(&object);
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_dtor */
+static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+
+ if (iterator->intern.data) {
+ zval *object = iterator->intern.data;
+ zval_ptr_dtor(&object);
+ }
+ /* Otherwise we were called from the owning object free storage handler as
+ * it sets
+ * iterator->intern.data to NULL.
+ * We don't even need to destroy iterator->current as we didn't add a
+ * reference to it in move_forward or get_iterator */
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_valid */
+static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
+
+ return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_current_data */
+static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+
+ *data = &iterator->current;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_current_key */
+static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
+
+ *int_key = object->u.dir.index;
+ return HASH_KEY_IS_LONG;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_move_forward */
+static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
+
+ object->u.dir.index++;
+ spl_filesystem_dir_read(object TSRMLS_CC);
+ if (object->file_name) {
+ efree(object->file_name);
+ object->file_name = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ spl_filesystem_dir_it_rewind */
+static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
+
+ object->u.dir.index = 0;
+ if (object->u.dir.dirp) {
+ php_stream_rewinddir(object->u.dir.dirp);
+ }
+ spl_filesystem_dir_read(object TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_filesystem_tree_it_dtor */
+static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+
+ if (iterator->intern.data) {
+ zval *object = iterator->intern.data;
+ zval_ptr_dtor(&object);
+ } else {
+ if (iterator->current) {
+ zval_ptr_dtor(&iterator->current);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ spl_filesystem_tree_it_current_data */
+static void spl_filesystem_tree_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
+
+ if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
+ if (!iterator->current) {
+ ALLOC_INIT_ZVAL(iterator->current);
+ spl_filesystem_object_get_file_name(object TSRMLS_CC);
+ ZVAL_STRINGL(iterator->current, object->file_name, object->file_name_len, 1);
+ }
+ *data = &iterator->current;
+ } else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
+ if (!iterator->current) {
+ ALLOC_INIT_ZVAL(iterator->current);
+ spl_filesystem_object_get_file_name(object TSRMLS_CC);
+ spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, iterator->current TSRMLS_CC);
+ }
+ *data = &iterator->current;
+ } else {
+ *data = (zval**)&iterator->intern.data;
+ }
+}
+/* }}} */
+
+/* {{{ spl_filesystem_tree_it_current_key */
+static int spl_filesystem_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
+
+ if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
+ *str_key_len = strlen(object->u.dir.entry.d_name) + 1;
+ *str_key = estrndup(object->u.dir.entry.d_name, *str_key_len - 1);
+ } else {
+ spl_filesystem_object_get_file_name(object TSRMLS_CC);
+ *str_key_len = object->file_name_len + 1;
+ *str_key = estrndup(object->file_name, object->file_name_len);
+ }
+ return HASH_KEY_IS_STRING;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_tree_it_move_forward */
+static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
+
+ object->u.dir.index++;
+ do {
+ spl_filesystem_dir_read(object TSRMLS_CC);
+ } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
+ if (object->file_name) {
+ efree(object->file_name);
+ object->file_name = NULL;
+ }
+ if (iterator->current) {
+ zval_ptr_dtor(&iterator->current);
+ iterator->current = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ spl_filesystem_tree_it_rewind */
+static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
+ spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
+
+ object->u.dir.index = 0;
+ if (object->u.dir.dirp) {
+ php_stream_rewinddir(object->u.dir.dirp);
+ }
+ do {
+ spl_filesystem_dir_read(object TSRMLS_CC);
+ } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
+ if (iterator->current) {
+ zval_ptr_dtor(&iterator->current);
+ iterator->current = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ iterator handler table */
+zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
+ spl_filesystem_tree_it_dtor,
+ spl_filesystem_dir_it_valid,
+ spl_filesystem_tree_it_current_data,
+ spl_filesystem_tree_it_current_key,
+ spl_filesystem_tree_it_move_forward,
+ spl_filesystem_tree_it_rewind
+};
+/* }}} */
+
+/* {{{ spl_ce_dir_get_iterator */
+zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
+{
+ spl_filesystem_iterator *iterator;
+ spl_filesystem_object *dir_object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
+ iterator = spl_filesystem_object_to_iterator(dir_object);
+
+ /* initialize iterator if wasn't gotten before */
+ if (iterator->intern.data == NULL) {
+ iterator->intern.data = object;
+ iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
+ }
+ zval_add_ref(&object);
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+/* {{{ spl_filesystem_object_cast */
+static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
+
+ if (type == IS_STRING) {
+ if (Z_OBJCE_P(readobj)->__tostring) {
+ return std_object_handlers.cast_object(readobj, writeobj, type TSRMLS_CC);
+ }
+
+ switch (intern->type) {
+ case SPL_FS_INFO:
+ case SPL_FS_FILE:
+ if (readobj == writeobj) {
+ zval retval;
+ zval *retval_ptr = &retval;
+
+ ZVAL_STRINGL(retval_ptr, intern->file_name, intern->file_name_len, 1);
+ zval_dtor(readobj);
+ ZVAL_ZVAL(writeobj, retval_ptr, 0, 0);
+ } else {
+ ZVAL_STRINGL(writeobj, intern->file_name, intern->file_name_len, 1);
+ }
+ return SUCCESS;
+ case SPL_FS_DIR:
+ if (readobj == writeobj) {
+ zval retval;
+ zval *retval_ptr = &retval;
+
+ ZVAL_STRING(retval_ptr, intern->u.dir.entry.d_name, 1);
+ zval_dtor(readobj);
+ ZVAL_ZVAL(writeobj, retval_ptr, 0, 0);
+ } else {
+ ZVAL_STRING(writeobj, intern->u.dir.entry.d_name, 1);
+ }
+ return SUCCESS;
+ }
+ }
+ if (readobj == writeobj) {
+ zval_dtor(readobj);
+ }
+ ZVAL_NULL(writeobj);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ declare method parameters */
+/* supply a name and default to call by parameter */
+ZEND_BEGIN_ARG_INFO(arginfo_info___construct, 0)
+ ZEND_ARG_INFO(0, file_name)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_info_openFile, 0, 0, 0)
+ ZEND_ARG_INFO(0, open_mode)
+ ZEND_ARG_INFO(0, use_include_path)
+ ZEND_ARG_INFO(0, context)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_info_optinalFileClass, 0, 0, 0)
+ ZEND_ARG_INFO(0, class_name)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_optinalSuffix, 0, 0, 0)
+ ZEND_ARG_INFO(0, suffix)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_splfileinfo_void, 0)
+ZEND_END_ARG_INFO()
+
+/* the method table */
+/* each method can have its own parameters and visibility */
+static const zend_function_entry spl_SplFileInfo_functions[] = {
+ SPL_ME(SplFileInfo, __construct, arginfo_info___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getExtension, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getBasename, arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getPerms, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getInode, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getSize, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getOwner, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getGroup, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getATime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getMTime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getCTime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getType, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isWritable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isReadable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isExecutable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isFile, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isDir, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, isLink, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getLinkTarget, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+#if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS)
+ SPL_ME(SplFileInfo, getRealPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+#endif
+ SPL_ME(SplFileInfo, getFileInfo, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, getPathInfo, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, openFile, arginfo_info_openFile, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, setFileClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, setInfoClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileInfo, _bad_state_ex, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+ SPL_MA(SplFileInfo, __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0)
+ ZEND_ARG_INFO(0, path)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_dir_it_seek, 0)
+ ZEND_ARG_INFO(0, position)
+ZEND_END_ARG_INFO();
+
+/* the method table */
+/* each method can have its own parameters and visibility */
+static const zend_function_entry spl_DirectoryIterator_functions[] = {
+ SPL_ME(DirectoryIterator, __construct, arginfo_dir___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, getExtension, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, getBasename, arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, isDot, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, valid, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, seek, arginfo_dir_it_seek, ZEND_ACC_PUBLIC)
+ SPL_MA(DirectoryIterator, __toString, DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir___construct, 0, 0, 1)
+ ZEND_ARG_INFO(0, path)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_hasChildren, 0, 0, 0)
+ ZEND_ARG_INFO(0, allow_links)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_setFlags, 0, 0, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_FilesystemIterator_functions[] = {
+ SPL_ME(FilesystemIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(FilesystemIterator, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(DirectoryIterator, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(FilesystemIterator, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(FilesystemIterator, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(FilesystemIterator, getFlags, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(FilesystemIterator, setFlags, arginfo_r_dir_setFlags, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_RecursiveDirectoryIterator_functions[] = {
+ SPL_ME(RecursiveDirectoryIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveDirectoryIterator, hasChildren, arginfo_r_dir_hasChildren, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveDirectoryIterator, getChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveDirectoryIterator, getSubPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveDirectoryIterator, getSubPathname,arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+#ifdef HAVE_GLOB
+static const zend_function_entry spl_GlobIterator_functions[] = {
+ SPL_ME(GlobIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(GlobIterator, count, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+#endif
+/* }}} */
+
+static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
+{
+ char *buf;
+ size_t line_len = 0;
+ long line_add = (intern->u.file.current_line || intern->u.file.current_zval) ? 1 : 0;
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+
+ if (php_stream_eof(intern->u.file.stream)) {
+ if (!silent) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
+ }
+ return FAILURE;
+ }
+
+ if (intern->u.file.max_line_len > 0) {
+ buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0);
+ if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len, &line_len) == NULL) {
+ efree(buf);
+ buf = NULL;
+ } else {
+ buf[line_len] = '\0';
+ }
+ } else {
+ buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len);
+ }
+
+ if (!buf) {
+ intern->u.file.current_line = estrdup("");
+ intern->u.file.current_line_len = 0;
+ } else {
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) {
+ line_len = strcspn(buf, "\r\n");
+ buf[line_len] = '\0';
+ }
+
+ intern->u.file.current_line = buf;
+ intern->u.file.current_line_len = line_len;
+ }
+ intern->u.file.current_line_num += line_add;
+
+ return SUCCESS;
+} /* }}} */
+
+static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function *func_ptr, int pass_num_args, zval *return_value, zval *arg2 TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcic;
+ zval z_fname;
+ zval * zresource_ptr = &intern->u.file.zresource, *retval;
+ int result;
+ int num_args = pass_num_args + (arg2 ? 2 : 1);
+
+ zval ***params = (zval***)safe_emalloc(num_args, sizeof(zval**), 0);
+
+ params[0] = &zresource_ptr;
+
+ if (arg2) {
+ params[1] = &arg2;
+ }
+
+ zend_get_parameters_array_ex(pass_num_args, params+(arg2 ? 2 : 1));
+
+ ZVAL_STRING(&z_fname, func_ptr->common.function_name, 0);
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.object_ptr = NULL;
+ fci.function_name = &z_fname;
+ fci.retval_ptr_ptr = &retval;
+ fci.param_count = num_args;
+ fci.params = params;
+ fci.no_separation = 1;
+ fci.symbol_table = NULL;
+
+ fcic.initialized = 1;
+ fcic.function_handler = func_ptr;
+ fcic.calling_scope = NULL;
+ fcic.called_scope = NULL;
+ fcic.object_ptr = NULL;
+
+ result = zend_call_function(&fci, &fcic TSRMLS_CC);
+
+ if (result == FAILURE) {
+ RETVAL_FALSE;
+ } else {
+ ZVAL_ZVAL(return_value, retval, 1, 1);
+ }
+
+ efree(params);
+ return result;
+} /* }}} */
+
+#define FileFunctionCall(func_name, pass_num_args, arg2) /* {{{ */ \
+{ \
+ zend_function *func_ptr; \
+ int ret; \
+ ret = zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
+ if (ret != SUCCESS) { \
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Internal error, function '%s' not found. Please report", #func_name); \
+ return; \
+ } \
+ spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2 TSRMLS_CC); \
+} /* }}} */
+
+static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, char escape, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ int ret = SUCCESS;
+
+ do {
+ ret = spl_filesystem_file_read(intern, 1 TSRMLS_CC);
+ } while (ret == SUCCESS && !intern->u.file.current_line_len && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY));
+
+ if (ret == SUCCESS) {
+ size_t buf_len = intern->u.file.current_line_len;
+ char *buf = estrndup(intern->u.file.current_line, buf_len);
+
+ if (intern->u.file.current_zval) {
+ zval_ptr_dtor(&intern->u.file.current_zval);
+ }
+ ALLOC_INIT_ZVAL(intern->u.file.current_zval);
+
+ php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf, intern->u.file.current_zval TSRMLS_CC);
+ if (return_value) {
+ if (Z_TYPE_P(return_value) != IS_NULL) {
+ zval_dtor(return_value);
+ ZVAL_NULL(return_value);
+ }
+ ZVAL_ZVAL(return_value, intern->u.file.current_zval, 1, 0);
+ }
+ }
+ return ret;
+}
+/* }}} */
+
+static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
+{
+ zval *retval = NULL;
+
+ /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
+ if (php_stream_eof(intern->u.file.stream)) {
+ if (!silent) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
+ }
+ return FAILURE;
+ }
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
+ return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL TSRMLS_CC);
+ } else {
+ zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
+ }
+ if (retval) {
+ if (intern->u.file.current_line || intern->u.file.current_zval) {
+ intern->u.file.current_line_num++;
+ }
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ if (Z_TYPE_P(retval) == IS_STRING) {
+ intern->u.file.current_line = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+ intern->u.file.current_line_len = Z_STRLEN_P(retval);
+ } else {
+ MAKE_STD_ZVAL(intern->u.file.current_zval);
+ ZVAL_ZVAL(intern->u.file.current_zval, retval, 1, 0);
+ }
+ zval_ptr_dtor(&retval);
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+ } else {
+ return spl_filesystem_file_read(intern, silent TSRMLS_CC);
+ }
+} /* }}} */
+
+static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (intern->u.file.current_line) {
+ return intern->u.file.current_line_len == 0;
+ } else if (intern->u.file.current_zval) {
+ switch(Z_TYPE_P(intern->u.file.current_zval)) {
+ case IS_STRING:
+ return Z_STRLEN_P(intern->u.file.current_zval) == 0;
+ case IS_ARRAY:
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)
+ && zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 1) {
+ zval ** first = Z_ARRVAL_P(intern->u.file.current_zval)->pListHead->pData;
+
+ return Z_TYPE_PP(first) == IS_STRING && Z_STRLEN_PP(first) == 0;
+ }
+ return zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 0;
+ case IS_NULL:
+ return 1;
+ default:
+ return 0;
+ }
+ } else {
+ return 1;
+ }
+}
+/* }}} */
+
+static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
+{
+ int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
+
+ while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern TSRMLS_CC)) {
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
+ }
+
+ return ret;
+}
+/* }}} */
+
+static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (-1 == php_stream_rewind(intern->u.file.stream)) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
+ } else {
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ intern->u.file.current_line_num = 0;
+ }
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
+ spl_filesystem_file_read_line(this_ptr, intern, 1 TSRMLS_CC);
+ }
+} /* }}} */
+
+/* {{{ proto void SplFileObject::__construct(string filename [, string mode = 'r' [, bool use_include_path [, resource context]]]])
+ Construct a new file object */
+SPL_METHOD(SplFileObject, __construct)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_bool use_include_path = 0;
+ char *p1, *p2;
+ char *tmp_path;
+ int tmp_path_len;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ intern->u.file.open_mode = NULL;
+ intern->u.file.open_mode_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|sbr",
+ &intern->file_name, &intern->file_name_len,
+ &intern->u.file.open_mode, &intern->u.file.open_mode_len,
+ &use_include_path, &intern->u.file.zcontext) == FAILURE) {
+ intern->u.file.open_mode = NULL;
+ intern->file_name = NULL;
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ if (intern->u.file.open_mode == NULL) {
+ intern->u.file.open_mode = "r";
+ intern->u.file.open_mode_len = 1;
+ }
+
+ if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == SUCCESS) {
+ tmp_path_len = strlen(intern->u.file.stream->orig_path);
+
+ if (tmp_path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, tmp_path_len-1)) {
+ tmp_path_len--;
+ }
+
+ tmp_path = estrndup(intern->u.file.stream->orig_path, tmp_path_len);
+
+ p1 = strrchr(tmp_path, '/');
+#if defined(PHP_WIN32) || defined(NETWARE)
+ p2 = strrchr(tmp_path, '\\');
+#else
+ p2 = 0;
+#endif
+ if (p1 || p2) {
+ intern->_path_len = (p1 > p2 ? p1 : p2) - tmp_path;
+ } else {
+ intern->_path_len = 0;
+ }
+
+ efree(tmp_path);
+
+ intern->_path = estrndup(intern->u.file.stream->orig_path, intern->_path_len);
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+
+} /* }}} */
+
+/* {{{ proto void SplTempFileObject::__construct([int max_memory])
+ Construct a new temp file object */
+SPL_METHOD(SplTempFileObject, __construct)
+{
+ long max_memory = PHP_STREAM_MAX_MEM;
+ char tmp_fname[48];
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_memory) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ if (max_memory < 0) {
+ intern->file_name = "php://memory";
+ intern->file_name_len = 12;
+ } else if (ZEND_NUM_ARGS()) {
+ intern->file_name_len = slprintf(tmp_fname, sizeof(tmp_fname), "php://temp/maxmemory:%ld", max_memory);
+ intern->file_name = tmp_fname;
+ } else {
+ intern->file_name = "php://temp";
+ intern->file_name_len = 10;
+ }
+ intern->u.file.open_mode = "wb";
+ intern->u.file.open_mode_len = 1;
+ intern->u.file.zcontext = NULL;
+
+ if (spl_filesystem_file_open(intern, 0, 0 TSRMLS_CC) == SUCCESS) {
+ intern->_path_len = 0;
+ intern->_path = estrndup("", 0);
+ }
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void SplFileObject::rewind()
+ Rewind the file and read the first line */
+SPL_METHOD(SplFileObject, rewind)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void SplFileObject::eof()
+ Return whether end of file is reached */
+SPL_METHOD(SplFileObject, eof)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(php_stream_eof(intern->u.file.stream));
+} /* }}} */
+
+/* {{{ proto void SplFileObject::valid()
+ Return !eof() */
+SPL_METHOD(SplFileObject, valid)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
+ RETURN_BOOL(intern->u.file.current_line || intern->u.file.current_zval);
+ } else {
+ RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
+ }
+} /* }}} */
+
+/* {{{ proto string SplFileObject::fgets()
+ Rturn next line from file */
+SPL_METHOD(SplFileObject, fgets)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (spl_filesystem_file_read(intern, 0 TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+ RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1);
+} /* }}} */
+
+/* {{{ proto string SplFileObject::current()
+ Return current line from file */
+SPL_METHOD(SplFileObject, current)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!intern->u.file.current_line && !intern->u.file.current_zval) {
+ spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
+ }
+ if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || !intern->u.file.current_zval)) {
+ RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1);
+ } else if (intern->u.file.current_zval) {
+ RETURN_ZVAL(intern->u.file.current_zval, 1, 0);
+ }
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto int SplFileObject::key()
+ Return line number */
+SPL_METHOD(SplFileObject, key)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+/* Do not read the next line to support correct counting with fgetc()
+ if (!intern->current_line) {
+ spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
+ } */
+ RETURN_LONG(intern->u.file.current_line_num);
+} /* }}} */
+
+/* {{{ proto void SplFileObject::next()
+ Read next line */
+SPL_METHOD(SplFileObject, next)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
+ spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
+ }
+ intern->u.file.current_line_num++;
+} /* }}} */
+
+/* {{{ proto void SplFileObject::setFlags(int flags)
+ Set file handling flags */
+SPL_METHOD(SplFileObject, setFlags)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
+ return;
+ }
+} /* }}} */
+
+/* {{{ proto int SplFileObject::getFlags()
+ Get file handling flags */
+SPL_METHOD(SplFileObject, getFlags)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
+} /* }}} */
+
+/* {{{ proto void SplFileObject::setMaxLineLen(int max_len)
+ Set maximum line length */
+SPL_METHOD(SplFileObject, setMaxLineLen)
+{
+ long max_len;
+
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &max_len) == FAILURE) {
+ return;
+ }
+
+ if (max_len < 0) {
+ zend_throw_exception_ex(spl_ce_DomainException, 0 TSRMLS_CC, "Maximum line length must be greater than or equal zero");
+ return;
+ }
+
+ intern->u.file.max_line_len = max_len;
+} /* }}} */
+
+/* {{{ proto int SplFileObject::getMaxLineLen()
+ Get maximum line length */
+SPL_METHOD(SplFileObject, getMaxLineLen)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG((long)intern->u.file.max_line_len);
+} /* }}} */
+
+/* {{{ proto bool SplFileObject::hasChildren()
+ Return false */
+SPL_METHOD(SplFileObject, hasChildren)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto bool SplFileObject::getChildren()
+ Read NULL */
+SPL_METHOD(SplFileObject, getChildren)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* return NULL */
+} /* }}} */
+
+/* {{{ FileFunction */
+#define FileFunction(func_name) \
+SPL_METHOD(SplFileObject, func_name) \
+{ \
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+ FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
+}
+/* }}} */
+
+/* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure [, escape = '\\']]])
+ Return current line as csv */
+SPL_METHOD(SplFileObject, fgetcsv)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
+ char *delim = NULL, *enclo = NULL, *esc = NULL;
+ int d_len = 0, e_len = 0, esc_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
+ switch(ZEND_NUM_ARGS())
+ {
+ case 3:
+ if (esc_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
+ RETURN_FALSE;
+ }
+ escape = esc[0];
+ /* no break */
+ case 2:
+ if (e_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
+ RETURN_FALSE;
+ }
+ enclosure = enclo[0];
+ /* no break */
+ case 1:
+ if (d_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
+ RETURN_FALSE;
+ }
+ delimiter = delim[0];
+ /* no break */
+ case 0:
+ break;
+ }
+ spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto int SplFileObject::fputcsv(array fields, [string delimiter [, string enclosure]])
+ Output a field array as a CSV line */
+SPL_METHOD(SplFileObject, fputcsv)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
+ char *delim = NULL, *enclo = NULL;
+ int d_len = 0, e_len = 0, ret;
+ zval *fields = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &fields, &delim, &d_len, &enclo, &e_len) == SUCCESS) {
+ switch(ZEND_NUM_ARGS())
+ {
+ case 3:
+ if (e_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
+ RETURN_FALSE;
+ }
+ enclosure = enclo[0];
+ /* no break */
+ case 2:
+ if (d_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
+ RETURN_FALSE;
+ }
+ delimiter = delim[0];
+ /* no break */
+ case 1:
+ case 0:
+ break;
+ }
+ ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape TSRMLS_CC);
+ RETURN_LONG(ret);
+ }
+}
+/* }}} */
+
+/* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"' [, string escape = '\\']]])
+ Set the delimiter and enclosure character used in fgetcsv */
+SPL_METHOD(SplFileObject, setCsvControl)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter = ',', enclosure = '"', escape='\\';
+ char *delim = NULL, *enclo = NULL, *esc = NULL;
+ int d_len = 0, e_len = 0, esc_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
+ switch(ZEND_NUM_ARGS())
+ {
+ case 3:
+ if (esc_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
+ RETURN_FALSE;
+ }
+ escape = esc[0];
+ /* no break */
+ case 2:
+ if (e_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
+ RETURN_FALSE;
+ }
+ enclosure = enclo[0];
+ /* no break */
+ case 1:
+ if (d_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
+ RETURN_FALSE;
+ }
+ delimiter = delim[0];
+ /* no break */
+ case 0:
+ break;
+ }
+ intern->u.file.delimiter = delimiter;
+ intern->u.file.enclosure = enclosure;
+ intern->u.file.escape = escape;
+ }
+}
+/* }}} */
+
+/* {{{ proto array SplFileObject::getCsvControl()
+ Get the delimiter and enclosure character used in fgetcsv */
+SPL_METHOD(SplFileObject, getCsvControl)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter[2], enclosure[2];
+
+ array_init(return_value);
+
+ delimiter[0] = intern->u.file.delimiter;
+ delimiter[1] = '\0';
+ enclosure[0] = intern->u.file.enclosure;
+ enclosure[1] = '\0';
+
+ add_next_index_string(return_value, delimiter, 1);
+ add_next_index_string(return_value, enclosure, 1);
+}
+/* }}} */
+
+/* {{{ proto bool SplFileObject::flock(int operation [, int &wouldblock])
+ Portable file locking */
+FileFunction(flock)
+/* }}} */
+
+/* {{{ proto bool SplFileObject::fflush()
+ Flush the file */
+SPL_METHOD(SplFileObject, fflush)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
+} /* }}} */
+
+/* {{{ proto int SplFileObject::ftell()
+ Return current file position */
+SPL_METHOD(SplFileObject, ftell)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long ret = php_stream_tell(intern->u.file.stream);
+
+ if (ret == -1) {
+ RETURN_FALSE;
+ } else {
+ RETURN_LONG(ret);
+ }
+} /* }}} */
+
+/* {{{ proto int SplFileObject::fseek(int pos [, int whence = SEEK_SET])
+ Return current file position */
+SPL_METHOD(SplFileObject, fseek)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long pos, whence = SEEK_SET;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &pos, &whence) == FAILURE) {
+ return;
+ }
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, whence));
+} /* }}} */
+
+/* {{{ proto int SplFileObject::fgetc()
+ Get a character form the file */
+SPL_METHOD(SplFileObject, fgetc)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char buf[2];
+ int result;
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+
+ result = php_stream_getc(intern->u.file.stream);
+
+ if (result == EOF) {
+ RETVAL_FALSE;
+ } else {
+ if (result == '\n') {
+ intern->u.file.current_line_num++;
+ }
+ buf[0] = result;
+ buf[1] = '\0';
+
+ RETURN_STRINGL(buf, 1, 1);
+ }
+} /* }}} */
+
+/* {{{ proto string SplFileObject::fgetss([string allowable_tags])
+ Get a line from file pointer and strip HTML tags */
+SPL_METHOD(SplFileObject, fgetss)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *arg2 = NULL;
+ MAKE_STD_ZVAL(arg2);
+
+ if (intern->u.file.max_line_len > 0) {
+ ZVAL_LONG(arg2, intern->u.file.max_line_len);
+ } else {
+ ZVAL_LONG(arg2, 1024);
+ }
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ intern->u.file.current_line_num++;
+
+ FileFunctionCall(fgetss, ZEND_NUM_ARGS(), arg2);
+
+ zval_ptr_dtor(&arg2);
+} /* }}} */
+
+/* {{{ proto int SplFileObject::fpassthru()
+ Output all remaining data from a file pointer */
+SPL_METHOD(SplFileObject, fpassthru)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(php_stream_passthru(intern->u.file.stream));
+} /* }}} */
+
+/* {{{ proto bool SplFileObject::fscanf(string format [, string ...])
+ Implements a mostly ANSI compatible fscanf() */
+SPL_METHOD(SplFileObject, fscanf)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ intern->u.file.current_line_num++;
+
+ FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
+}
+/* }}} */
+
+/* {{{ proto mixed SplFileObject::fwrite(string str [, int length])
+ Binary-safe file write */
+SPL_METHOD(SplFileObject, fwrite)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *str;
+ int str_len;
+ long length = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &length) == FAILURE) {
+ return;
+ }
+
+ if (ZEND_NUM_ARGS() > 1) {
+ str_len = MAX(0, MIN(length, str_len));
+ }
+ if (!str_len) {
+ RETURN_LONG(0);
+ }
+
+ RETURN_LONG(php_stream_write(intern->u.file.stream, str, str_len));
+} /* }}} */
+
+/* {{{ proto bool SplFileObject::fstat()
+ Stat() on a filehandle */
+FileFunction(fstat)
+/* }}} */
+
+/* {{{ proto bool SplFileObject::ftruncate(int size)
+ Truncate file to 'size' length */
+SPL_METHOD(SplFileObject, ftruncate)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long size;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) {
+ return;
+ }
+
+ if (!php_stream_truncate_supported(intern->u.file.stream)) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't truncate file %s", intern->file_name);
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size));
+} /* }}} */
+
+/* {{{ proto void SplFileObject::seek(int line_pos)
+ Seek to specified line */
+SPL_METHOD(SplFileObject, seek)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long line_pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &line_pos) == FAILURE) {
+ return;
+ }
+ if (line_pos < 0) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't seek file %s to negative line %ld", intern->file_name, line_pos);
+ RETURN_FALSE;
+ }
+
+ spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
+
+ while(intern->u.file.current_line_num < line_pos) {
+ if (spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC) == FAILURE) {
+ break;
+ }
+ }
+} /* }}} */
+
+/* {{{ Function/Class/Method definitions */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object___construct, 0, 0, 1)
+ ZEND_ARG_INFO(0, file_name)
+ ZEND_ARG_INFO(0, open_mode)
+ ZEND_ARG_INFO(0, use_include_path)
+ ZEND_ARG_INFO(0, context)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_file_object_setFlags, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_file_object_setMaxLineLen, 0)
+ ZEND_ARG_INFO(0, max_len)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetcsv, 0, 0, 0)
+ ZEND_ARG_INFO(0, delimiter)
+ ZEND_ARG_INFO(0, enclosure)
+ ZEND_ARG_INFO(0, escape)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fputcsv, 0, 0, 1)
+ ZEND_ARG_INFO(0, fields)
+ ZEND_ARG_INFO(0, delimiter)
+ ZEND_ARG_INFO(0, enclosure)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_flock, 0, 0, 1)
+ ZEND_ARG_INFO(0, operation)
+ ZEND_ARG_INFO(1, wouldblock)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fseek, 0, 0, 1)
+ ZEND_ARG_INFO(0, pos)
+ ZEND_ARG_INFO(0, whence)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0)
+ ZEND_ARG_INFO(0, allowable_tags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 1, 0, 1)
+ ZEND_ARG_INFO(0, format)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1)
+ ZEND_ARG_INFO(0, str)
+ ZEND_ARG_INFO(0, length)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1)
+ ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1)
+ ZEND_ARG_INFO(0, line_pos)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_SplFileObject_functions[] = {
+ SPL_ME(SplFileObject, __construct, arginfo_file_object___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, eof, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, valid, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fgets, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fgetcsv, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fputcsv, arginfo_file_object_fputcsv, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, setCsvControl, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, getCsvControl, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, flock, arginfo_file_object_flock, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fflush, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, ftell, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fseek, arginfo_file_object_fseek, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fgetc, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fpassthru, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fgetss, arginfo_file_object_fgetss, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fscanf, arginfo_file_object_fscanf, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fwrite, arginfo_file_object_fwrite, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, fstat, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, ftruncate, arginfo_file_object_ftruncate, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, setFlags, arginfo_file_object_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, getFlags, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, setMaxLineLen, arginfo_file_object_setMaxLineLen, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, getMaxLineLen, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, hasChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, getChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, seek, arginfo_file_object_seek, ZEND_ACC_PUBLIC)
+ /* mappings */
+ SPL_MA(SplFileObject, getCurrentLine, SplFileObject, fgets, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ SPL_MA(SplFileObject, __toString, SplFileObject, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0)
+ ZEND_ARG_INFO(0, max_memory)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_SplTempFileObject_functions[] = {
+ SPL_ME(SplTempFileObject, __construct, arginfo_temp_file_object___construct, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION(spl_directory)
+ */
+PHP_MINIT_FUNCTION(spl_directory)
+{
+ REGISTER_SPL_STD_CLASS_EX(SplFileInfo, spl_filesystem_object_new, spl_SplFileInfo_functions);
+ memcpy(&spl_filesystem_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone;
+ spl_filesystem_object_handlers.cast_object = spl_filesystem_object_cast;
+ spl_filesystem_object_handlers.get_debug_info = spl_filesystem_object_get_debug_info;
+ spl_ce_SplFileInfo->serialize = zend_class_serialize_deny;
+ spl_ce_SplFileInfo->unserialize = zend_class_unserialize_deny;
+
+ REGISTER_SPL_SUB_CLASS_EX(DirectoryIterator, SplFileInfo, spl_filesystem_object_new, spl_DirectoryIterator_functions);
+ zend_class_implements(spl_ce_DirectoryIterator TSRMLS_CC, 1, zend_ce_iterator);
+ 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);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_PATHNAME", SPL_FILE_DIR_CURRENT_AS_PATHNAME);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_FILEINFO", SPL_FILE_DIR_CURRENT_AS_FILEINFO);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_SELF", SPL_FILE_DIR_CURRENT_AS_SELF);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_MODE_MASK", SPL_FILE_DIR_KEY_MODE_MASK);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_PATHNAME", SPL_FILE_DIR_KEY_AS_PATHNAME);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "FOLLOW_SYMLINKS", SPL_FILE_DIR_FOLLOW_SYMLINKS);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_FILENAME", SPL_FILE_DIR_KEY_AS_FILENAME);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "NEW_CURRENT_AND_KEY", SPL_FILE_DIR_KEY_AS_FILENAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "OTHER_MODE_MASK", SPL_FILE_DIR_OTHERS_MASK);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "SKIP_DOTS", SPL_FILE_DIR_SKIPDOTS);
+ REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "UNIX_PATHS", SPL_FILE_DIR_UNIXPATHS);
+
+ spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator;
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions);
+ REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator);
+
+ memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
+ spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
+
+#ifdef HAVE_GLOB
+ REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new_check, spl_GlobIterator_functions);
+ REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable);
+#endif
+
+ REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new_check, spl_SplFileObject_functions);
+ REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator);
+ REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator);
+
+ REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
+ REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD", SPL_FILE_OBJECT_READ_AHEAD);
+ 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_check, spl_SplTempFileObject_functions);
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_directory.h b/ext/spl/spl_directory.h
new file mode 100644
index 0000000..d95ba55
--- /dev/null
+++ b/ext/spl/spl_directory.h
@@ -0,0 +1,149 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_DIRECTORY_H
+#define SPL_DIRECTORY_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_SplFileInfo;
+extern PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
+extern PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
+extern PHPAPI zend_class_entry *spl_ce_GlobIterator;
+extern PHPAPI zend_class_entry *spl_ce_SplFileObject;
+extern PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
+
+PHP_MINIT_FUNCTION(spl_directory);
+
+typedef enum {
+ SPL_FS_INFO, /* must be 0 */
+ SPL_FS_DIR,
+ SPL_FS_FILE
+} SPL_FS_OBJ_TYPE;
+
+typedef struct _spl_filesystem_object spl_filesystem_object;
+
+typedef void (*spl_foreign_dtor_t)(spl_filesystem_object *object TSRMLS_DC);
+typedef void (*spl_foreign_clone_t)(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC);
+
+PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC);
+
+typedef struct _spl_other_handler {
+ spl_foreign_dtor_t dtor;
+ spl_foreign_clone_t clone;
+} spl_other_handler;
+
+/* define an overloaded iterator structure */
+typedef struct {
+ zend_object_iterator intern;
+ zval *current;
+ spl_filesystem_object *object;
+} spl_filesystem_iterator;
+
+struct _spl_filesystem_object {
+ zend_object std;
+ void *oth;
+ spl_other_handler *oth_handler;
+ char *_path;
+ int _path_len;
+ char *orig_path;
+ char *file_name;
+ int file_name_len;
+ SPL_FS_OBJ_TYPE type;
+ long flags;
+ zend_class_entry *file_class;
+ zend_class_entry *info_class;
+ union {
+ struct {
+ php_stream *dirp;
+ php_stream_dirent entry;
+ char *sub_path;
+ int sub_path_len;
+ int index;
+ int is_recursive;
+ zend_function *func_rewind;
+ zend_function *func_next;
+ zend_function *func_valid;
+ } dir;
+ struct {
+ php_stream *stream;
+ php_stream_context *context;
+ zval *zcontext;
+ char *open_mode;
+ int open_mode_len;
+ zval *current_zval;
+ char *current_line;
+ size_t current_line_len;
+ size_t max_line_len;
+ long current_line_num;
+ zval zresource;
+ zend_function *func_getCurr;
+ char delimiter;
+ char enclosure;
+ char escape;
+ } file;
+ } u;
+ spl_filesystem_iterator it;
+};
+
+static inline spl_filesystem_iterator* spl_filesystem_object_to_iterator(spl_filesystem_object *obj)
+{
+ return &obj->it;
+}
+
+static inline spl_filesystem_object* spl_filesystem_iterator_to_object(spl_filesystem_iterator *it)
+{
+ return (spl_filesystem_object*)((char*)it - XtOffsetOf(spl_filesystem_object, it));
+}
+
+#define SPL_FILE_OBJECT_DROP_NEW_LINE 0x00000001 /* drop new lines */
+#define SPL_FILE_OBJECT_READ_AHEAD 0x00000002 /* read on rewind/next */
+#define SPL_FILE_OBJECT_SKIP_EMPTY 0x00000004 /* skip empty lines */
+#define SPL_FILE_OBJECT_READ_CSV 0x00000008 /* read via fgetcsv */
+#define SPL_FILE_OBJECT_MASK 0x0000000F /* read via fgetcsv */
+
+#define SPL_FILE_DIR_CURRENT_AS_FILEINFO 0x00000000 /* make RecursiveDirectoryTree::current() return SplFileInfo */
+#define SPL_FILE_DIR_CURRENT_AS_SELF 0x00000010 /* make RecursiveDirectoryTree::current() return getSelf() */
+#define SPL_FILE_DIR_CURRENT_AS_PATHNAME 0x00000020 /* make RecursiveDirectoryTree::current() return getPathname() */
+#define SPL_FILE_DIR_CURRENT_MODE_MASK 0x000000F0 /* mask RecursiveDirectoryTree::current() */
+#define SPL_FILE_DIR_CURRENT(intern,mode) ((intern->flags&SPL_FILE_DIR_CURRENT_MODE_MASK)==mode)
+
+#define SPL_FILE_DIR_KEY_AS_PATHNAME 0x00000000 /* make RecursiveDirectoryTree::key() return getPathname() */
+#define SPL_FILE_DIR_KEY_AS_FILENAME 0x00000100 /* make RecursiveDirectoryTree::key() return getFilename() */
+#define SPL_FILE_DIR_FOLLOW_SYMLINKS 0x00000200 /* make RecursiveDirectoryTree::hasChildren() follow symlinks */
+#define SPL_FILE_DIR_KEY_MODE_MASK 0x00000F00 /* mask RecursiveDirectoryTree::key() */
+#define SPL_FILE_DIR_KEY(intern,mode) ((intern->flags&SPL_FILE_DIR_KEY_MODE_MASK)==mode)
+
+#define SPL_FILE_DIR_SKIPDOTS 0x00001000 /* Tells whether it should skip dots or not */
+#define SPL_FILE_DIR_UNIXPATHS 0x00002000 /* Whether to unixify path separators */
+#define SPL_FILE_DIR_OTHERS_MASK 0x00003000 /* mask used for get/setFlags */
+
+#endif /* SPL_DIRECTORY_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c
new file mode 100644
index 0000000..a8417fe
--- /dev/null
+++ b/ext/spl/spl_dllist.c
@@ -0,0 +1,1376 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "zend_exceptions.h"
+#include "zend_hash.h"
+
+#include "php_spl.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/php_smart_str.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+#include "spl_dllist.h"
+#include "spl_exceptions.h"
+
+zend_object_handlers spl_handler_SplDoublyLinkedList;
+PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList;
+PHPAPI zend_class_entry *spl_ce_SplQueue;
+PHPAPI zend_class_entry *spl_ce_SplStack;
+
+#define SPL_LLIST_DELREF(elem) if(!--(elem)->rc) { \
+ efree(elem); \
+ elem = NULL; \
+}
+
+#define SPL_LLIST_CHECK_DELREF(elem) if((elem) && !--(elem)->rc) { \
+ efree(elem); \
+ elem = NULL; \
+}
+
+#define SPL_LLIST_ADDREF(elem) (elem)->rc++
+#define SPL_LLIST_CHECK_ADDREF(elem) if(elem) (elem)->rc++
+
+#define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */
+#define SPL_DLLIST_IT_LIFO 0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */
+#define SPL_DLLIST_IT_MASK 0x00000003 /* Mask to isolate flags related to iterators */
+#define SPL_DLLIST_IT_FIX 0x00000004 /* Backward/Forward bit is fixed */
+
+#ifdef accept
+#undef accept
+#endif
+
+typedef struct _spl_ptr_llist_element {
+ struct _spl_ptr_llist_element *prev;
+ struct _spl_ptr_llist_element *next;
+ int rc;
+ void *data;
+} spl_ptr_llist_element;
+
+typedef void (*spl_ptr_llist_dtor_func)(spl_ptr_llist_element * TSRMLS_DC);
+typedef void (*spl_ptr_llist_ctor_func)(spl_ptr_llist_element * TSRMLS_DC);
+
+typedef struct _spl_ptr_llist {
+ spl_ptr_llist_element *head;
+ spl_ptr_llist_element *tail;
+ spl_ptr_llist_dtor_func dtor;
+ spl_ptr_llist_ctor_func ctor;
+ int count;
+} spl_ptr_llist;
+
+typedef struct _spl_dllist_object spl_dllist_object;
+typedef struct _spl_dllist_it spl_dllist_it;
+
+struct _spl_dllist_object {
+ zend_object std;
+ spl_ptr_llist *llist;
+ int traverse_position;
+ spl_ptr_llist_element *traverse_pointer;
+ zval *retval;
+ int flags;
+ zend_function *fptr_offset_get;
+ zend_function *fptr_offset_set;
+ zend_function *fptr_offset_has;
+ zend_function *fptr_offset_del;
+ zend_function *fptr_count;
+ zend_class_entry *ce_get_iterator;
+ HashTable *debug_info;
+};
+
+/* define an overloaded iterator structure */
+struct _spl_dllist_it {
+ zend_user_iterator intern;
+ int traverse_position;
+ spl_ptr_llist_element *traverse_pointer;
+ int flags;
+ spl_dllist_object *object;
+};
+
+/* {{{ spl_ptr_llist */
+static void spl_ptr_llist_zval_dtor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
+ if (elem->data) {
+ zval_ptr_dtor((zval **)&elem->data);
+ }
+}
+/* }}} */
+
+static void spl_ptr_llist_zval_ctor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
+ Z_ADDREF_P((zval *)elem->data);
+}
+/* }}} */
+
+static spl_ptr_llist *spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor, spl_ptr_llist_dtor_func dtor) /* {{{ */
+{
+ spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist));
+
+ llist->head = NULL;
+ llist->tail = NULL;
+ llist->count = 0;
+ llist->dtor = dtor;
+ llist->ctor = ctor;
+
+ return llist;
+}
+/* }}} */
+
+static long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */
+{
+ return (long)llist->count;
+}
+/* }}} */
+
+static void spl_ptr_llist_destroy(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
+{
+ spl_ptr_llist_element *current = llist->head, *next;
+ spl_ptr_llist_dtor_func dtor = llist->dtor;
+
+ while (current) {
+ next = current->next;
+ if(current && dtor) {
+ dtor(current TSRMLS_CC);
+ }
+ SPL_LLIST_DELREF(current);
+ current = next;
+ }
+
+ efree(llist);
+}
+/* }}} */
+
+static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, long offset, int backward) /* {{{ */
+{
+
+ spl_ptr_llist_element *current;
+ int pos = 0;
+
+ if (backward) {
+ current = llist->tail;
+ } else {
+ current = llist->head;
+ }
+
+ while (current && pos < offset) {
+ pos++;
+ if (backward) {
+ current = current->prev;
+ } else {
+ current = current->next;
+ }
+ }
+
+ return current;
+}
+/* }}} */
+
+static void spl_ptr_llist_unshift(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
+{
+ spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
+
+ elem->data = data;
+ elem->rc = 1;
+ elem->prev = NULL;
+ elem->next = llist->head;
+
+ if (llist->head) {
+ llist->head->prev = elem;
+ } else {
+ llist->tail = elem;
+ }
+
+ llist->head = elem;
+ llist->count++;
+
+ if (llist->ctor) {
+ llist->ctor(elem TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static void spl_ptr_llist_push(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
+{
+ spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
+
+ elem->data = data;
+ elem->rc = 1;
+ elem->prev = llist->tail;
+ elem->next = NULL;
+
+ if (llist->tail) {
+ llist->tail->next = elem;
+ } else {
+ llist->head = elem;
+ }
+
+ llist->tail = elem;
+ llist->count++;
+
+ if (llist->ctor) {
+ llist->ctor(elem TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static void *spl_ptr_llist_pop(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
+{
+ void *data;
+ spl_ptr_llist_element *tail = llist->tail;
+
+ if (tail == NULL) {
+ return NULL;
+ }
+
+ if (tail->prev) {
+ tail->prev->next = NULL;
+ } else {
+ llist->head = NULL;
+ }
+
+ llist->tail = tail->prev;
+ llist->count--;
+ data = tail->data;
+
+ if (llist->dtor) {
+ llist->dtor(tail TSRMLS_CC);
+ }
+
+ tail->data = NULL;
+
+ SPL_LLIST_DELREF(tail);
+
+ return data;
+}
+/* }}} */
+
+static void *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */
+{
+ spl_ptr_llist_element *tail = llist->tail;
+
+ if (tail == NULL) {
+ return NULL;
+ } else {
+ return tail->data;
+ }
+}
+/* }}} */
+
+static void *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */
+{
+ spl_ptr_llist_element *head = llist->head;
+
+ if (head == NULL) {
+ return NULL;
+ } else {
+ return head->data;
+ }
+}
+/* }}} */
+
+static void *spl_ptr_llist_shift(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
+{
+ void *data;
+ spl_ptr_llist_element *head = llist->head;
+
+ if (head == NULL) {
+ return NULL;
+ }
+
+ if (head->next) {
+ head->next->prev = NULL;
+ } else {
+ llist->tail = NULL;
+ }
+
+ llist->head = head->next;
+ llist->count--;
+ data = head->data;
+
+ if (llist->dtor) {
+ llist->dtor(head TSRMLS_CC);
+ }
+ head->data = NULL;
+
+ SPL_LLIST_DELREF(head);
+
+ return data;
+}
+/* }}} */
+
+static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to TSRMLS_DC) /* {{{ */
+{
+ spl_ptr_llist_element *current = from->head, *next;
+ spl_ptr_llist_ctor_func ctor = from->ctor;
+
+ while (current) {
+ next = current->next;
+
+ if (ctor) {
+ ctor(current TSRMLS_CC);
+ }
+
+ spl_ptr_llist_push(to, current->data TSRMLS_CC);
+ current = next;
+ }
+
+}
+/* }}} */
+
+/* }}} */
+
+static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_object *intern = (spl_dllist_object *)object;
+ zval *tmp = NULL;
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+
+ while(intern->llist->count > 0) {
+ tmp = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
+ zval_ptr_dtor(&tmp);
+ }
+
+ spl_ptr_llist_destroy(intern->llist TSRMLS_CC);
+ SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
+ zval_ptr_dtor(&intern->retval);
+
+ if (intern->debug_info != NULL) {
+ zend_hash_destroy(intern->debug_info);
+ efree(intern->debug_info);
+ }
+
+ efree(object);
+}
+/* }}} */
+
+zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
+
+static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type, spl_dllist_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */
+{
+ zend_object_value retval;
+ spl_dllist_object *intern;
+ zend_class_entry *parent = class_type;
+ int inherited = 0;
+
+ intern = ecalloc(1, sizeof(spl_dllist_object));
+ *obj = intern;
+ ALLOC_INIT_ZVAL(intern->retval);
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ intern->flags = 0;
+ intern->traverse_position = 0;
+ intern->debug_info = NULL;
+
+ if (orig) {
+ spl_dllist_object *other = (spl_dllist_object*)zend_object_store_get_object(orig TSRMLS_CC);
+ intern->ce_get_iterator = other->ce_get_iterator;
+
+ if (clone_orig) {
+ intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(other->llist->ctor, other->llist->dtor);
+ spl_ptr_llist_copy(other->llist, intern->llist TSRMLS_CC);
+ intern->traverse_pointer = intern->llist->head;
+ SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
+ } else {
+ intern->llist = other->llist;
+ intern->traverse_pointer = intern->llist->head;
+ SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
+ }
+
+ intern->flags = other->flags;
+ } else {
+ intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(spl_ptr_llist_zval_ctor, spl_ptr_llist_zval_dtor);
+ intern->traverse_pointer = intern->llist->head;
+ SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
+ }
+
+ while (parent) {
+ if (parent == spl_ce_SplStack) {
+ intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO);
+ retval.handlers = &spl_handler_SplDoublyLinkedList;
+ } else if (parent == spl_ce_SplQueue) {
+ intern->flags |= SPL_DLLIST_IT_FIX;
+ retval.handlers = &spl_handler_SplDoublyLinkedList;
+ }
+
+ if (parent == spl_ce_SplDoublyLinkedList) {
+ retval.handlers = &spl_handler_SplDoublyLinkedList;
+ break;
+ }
+
+ parent = parent->parent;
+ inherited = 1;
+ }
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_dllist_object_free_storage, NULL TSRMLS_CC);
+
+ if (!parent) { /* this must never happen */
+ php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplDoublyLinkedList");
+ }
+ if (inherited) {
+ zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
+ if (intern->fptr_offset_get->common.scope == parent) {
+ intern->fptr_offset_get = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
+ if (intern->fptr_offset_set->common.scope == parent) {
+ intern->fptr_offset_set = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
+ if (intern->fptr_offset_has->common.scope == parent) {
+ intern->fptr_offset_has = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
+ if (intern->fptr_offset_del->common.scope == parent) {
+ intern->fptr_offset_del = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
+ if (intern->fptr_count->common.scope == parent) {
+ intern->fptr_count = NULL;
+ }
+ }
+
+ return retval;
+}
+/* }}} */
+
+static zend_object_value spl_dllist_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_object *tmp;
+ return spl_dllist_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static zend_object_value spl_dllist_object_clone(zval *zobject TSRMLS_DC) /* {{{ */
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_dllist_object *intern;
+
+ old_object = zend_objects_get_address(zobject TSRMLS_CC);
+ new_obj_val = spl_dllist_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
+ new_object = &intern->std;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ return new_obj_val;
+}
+/* }}} */
+
+static int spl_dllist_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_count) {
+ zval *rv;
+ zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ convert_to_long(intern->retval);
+ *count = (long) Z_LVAL_P(intern->retval);
+ return SUCCESS;
+ }
+ *count = 0;
+ return FAILURE;
+ }
+
+ *count = spl_ptr_llist_count(intern->llist);
+ return SUCCESS;
+}
+/* }}} */
+
+static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{{ */
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ spl_ptr_llist_element *current = intern->llist->head, *next;
+ zval *tmp, zrv, *dllist_array;
+ char *pnstr;
+ int pnlen;
+ int i = 0;
+
+ *is_temp = 0;
+
+ if (intern->debug_info == NULL) {
+ ALLOC_HASHTABLE(intern->debug_info);
+ zend_hash_init(intern->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
+ }
+
+ if (intern->debug_info->nApplyCount == 0) {
+ INIT_PZVAL(&zrv);
+ Z_ARRVAL(zrv) = intern->debug_info;
+
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC);
+ add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags);
+ efree(pnstr);
+
+ ALLOC_INIT_ZVAL(dllist_array);
+ array_init(dllist_array);
+
+ while (current) {
+ next = current->next;
+
+ add_index_zval(dllist_array, i, (zval *)current->data);
+ Z_ADDREF_P(current->data);
+ i++;
+
+ current = next;
+ }
+
+ pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC);
+ add_assoc_zval_ex(&zrv, pnstr, pnlen+1, dllist_array);
+ efree(pnstr);
+ }
+
+ return intern->debug_info;
+}
+/* }}}} */
+
+/* {{{ proto bool SplDoublyLinkedList::push(mixed $value) U
+ Push $value on the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, push)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+ return;
+ }
+
+ SEPARATE_ARG_IF_REF(value);
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool SplDoublyLinkedList::unshift(mixed $value) U
+ Unshift $value on the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, unshift)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+ return;
+ }
+
+ SEPARATE_ARG_IF_REF(value);
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_ptr_llist_unshift(intern->llist, value TSRMLS_CC);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto mixed SplDoublyLinkedList::pop() U
+ Pop an element out of the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, pop)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ value = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
+
+ if (value == NULL) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 1);
+}
+/* }}} */
+
+/* {{{ proto mixed SplDoublyLinkedList::shift() U
+ Shift an element out of the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, shift)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ value = (zval *)spl_ptr_llist_shift(intern->llist TSRMLS_CC);
+
+ if (value == NULL) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 1);
+}
+/* }}} */
+
+/* {{{ proto mixed SplDoublyLinkedList::top() U
+ Peek at the top element of the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, top)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ value = (zval *)spl_ptr_llist_last(intern->llist);
+
+ if (value == NULL) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed SplDoublyLinkedList::bottom() U
+ Peek at the bottom element of the SplDoublyLinkedList */
+SPL_METHOD(SplDoublyLinkedList, bottom)
+{
+ zval *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ value = (zval *)spl_ptr_llist_first(intern->llist);
+
+ if (value == NULL) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto int SplDoublyLinkedList::count() U
+ Return the number of elements in the datastructure. */
+SPL_METHOD(SplDoublyLinkedList, count)
+{
+ long count;
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ count = spl_ptr_llist_count(intern->llist);
+ RETURN_LONG(count);
+}
+/* }}} */
+
+/* {{{ proto int SplDoublyLinkedList::isEmpty() U
+ Return true if the SplDoublyLinkedList is empty. */
+SPL_METHOD(SplDoublyLinkedList, isEmpty)
+{
+ long count;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ spl_dllist_object_count_elements(getThis(), &count TSRMLS_CC);
+ RETURN_BOOL(count==0);
+}
+/* }}} */
+
+/* {{{ proto int SplDoublyLinkedList::setIteratorMode($flags) U
+ Set the mode of iteration */
+SPL_METHOD(SplDoublyLinkedList, setIteratorMode)
+{
+ long value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->flags & SPL_DLLIST_IT_FIX
+ && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) {
+ zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0 TSRMLS_CC);
+ return;
+ }
+
+ intern->flags = value & SPL_DLLIST_IT_MASK;
+
+ RETURN_LONG(intern->flags);
+}
+/* }}} */
+
+/* {{{ proto int SplDoublyLinkedList::getIteratorMode() U
+ Return the mode of iteration */
+SPL_METHOD(SplDoublyLinkedList, getIteratorMode)
+{
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(intern->flags);
+}
+/* }}} */
+
+/* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U
+ Returns whether the requested $index exists. */
+SPL_METHOD(SplDoublyLinkedList, offsetExists)
+{
+ zval *zindex;
+ spl_dllist_object *intern;
+ long index;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ index = spl_offset_convert_to_long(zindex TSRMLS_CC);
+
+ RETURN_BOOL(index >= 0 && index < intern->llist->count);
+} /* }}} */
+
+/* {{{ proto mixed SplDoublyLinkedList::offsetGet(mixed $index) U
+ Returns the value at the specified $index. */
+SPL_METHOD(SplDoublyLinkedList, offsetGet)
+{
+ zval *zindex, *value;
+ long index;
+ spl_dllist_object *intern;
+ spl_ptr_llist_element *element;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ index = spl_offset_convert_to_long(zindex TSRMLS_CC);
+
+ if (index < 0 || index >= intern->llist->count) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
+ return;
+ }
+
+ element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
+
+ if (element != NULL) {
+ value = (zval *)element->data;
+ RETURN_ZVAL(value, 1, 0);
+ } else {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
+ return;
+ }
+} /* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) U
+ Sets the value at the specified $index to $newval. */
+SPL_METHOD(SplDoublyLinkedList, offsetSet)
+{
+ zval *zindex, *value;
+ spl_dllist_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
+ return;
+ }
+ SEPARATE_ARG_IF_REF(value);
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (Z_TYPE_P(zindex) == IS_NULL) {
+ /* $obj[] = ... */
+ spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
+ } else {
+ /* $obj[$foo] = ... */
+ long index;
+ spl_ptr_llist_element *element;
+
+ index = spl_offset_convert_to_long(zindex TSRMLS_CC);
+
+ if (index < 0 || index >= intern->llist->count) {
+ zval_ptr_dtor(&value);
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
+ return;
+ }
+
+ element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
+
+ if (element != NULL) {
+ /* call dtor on the old element as in spl_ptr_llist_pop */
+ if (intern->llist->dtor) {
+ intern->llist->dtor(element TSRMLS_CC);
+ }
+
+ /* the element is replaced, delref the old one as in
+ * SplDoublyLinkedList::pop() */
+ zval_ptr_dtor((zval **)&element->data);
+ element->data = value;
+
+ /* new element, call ctor as in spl_ptr_llist_push */
+ if (intern->llist->ctor) {
+ intern->llist->ctor(element TSRMLS_CC);
+ }
+ } else {
+ zval_ptr_dtor(&value);
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
+ return;
+ }
+ }
+} /* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::offsetUnset(mixed $index) U
+ Unsets the value at the specified $index. */
+SPL_METHOD(SplDoublyLinkedList, offsetUnset)
+{
+ zval *zindex;
+ long index;
+ spl_dllist_object *intern;
+ spl_ptr_llist_element *element;
+ spl_ptr_llist *llist;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ index = (int)spl_offset_convert_to_long(zindex TSRMLS_CC);
+ llist = intern->llist;
+
+ if (index < 0 || index >= intern->llist->count) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range", 0 TSRMLS_CC);
+ return;
+ }
+
+ element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
+
+ if (element != NULL) {
+ /* connect the neightbors */
+ if (element->prev) {
+ element->prev->next = element->next;
+ }
+
+ if (element->next) {
+ element->next->prev = element->prev;
+ }
+
+ /* take care of head/tail */
+ if (element == llist->head) {
+ llist->head = element->next;
+ }
+
+ if (element == llist->tail) {
+ llist->tail = element->prev;
+ }
+
+ /* finally, delete the element */
+ llist->count--;
+
+ if(llist->dtor) {
+ llist->dtor(element TSRMLS_CC);
+ }
+
+ zval_ptr_dtor((zval **)&element->data);
+ element->data = NULL;
+
+ SPL_LLIST_DELREF(element);
+ } else {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
+ return;
+ }
+} /* }}} */
+
+static void spl_dllist_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+
+ SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer);
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ zval_ptr_dtor((zval**)&iterator->intern.it.data);
+
+ efree(iterator);
+}
+/* }}} */
+
+static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */
+{
+ SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr);
+
+ if (flags & SPL_DLLIST_IT_LIFO) {
+ *traverse_position_ptr = llist->count-1;
+ *traverse_pointer_ptr = llist->tail;
+ } else {
+ *traverse_position_ptr = 0;
+ *traverse_pointer_ptr = llist->head;
+ }
+
+ SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
+}
+/* }}} */
+
+static void spl_dllist_it_helper_move_forward(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */
+{
+ if (*traverse_pointer_ptr) {
+ spl_ptr_llist_element *old = *traverse_pointer_ptr;
+
+ if (flags & SPL_DLLIST_IT_LIFO) {
+ *traverse_pointer_ptr = old->prev;
+ (*traverse_position_ptr)--;
+
+ if (flags & SPL_DLLIST_IT_DELETE) {
+ zval *prev = (zval *)spl_ptr_llist_pop(llist TSRMLS_CC);
+
+ if (prev) {
+ zval_ptr_dtor((zval **)&prev);
+ }
+ }
+ } else {
+ *traverse_pointer_ptr = old->next;
+
+ if (flags & SPL_DLLIST_IT_DELETE) {
+ zval *prev = (zval *)spl_ptr_llist_shift(llist TSRMLS_CC);
+
+ if (prev) {
+ zval_ptr_dtor((zval **)&prev);
+ }
+ } else {
+ (*traverse_position_ptr)++;
+ }
+ }
+
+ SPL_LLIST_DELREF(old);
+ SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
+ }
+}
+/* }}} */
+
+static void spl_dllist_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+ spl_dllist_object *object = iterator->object;
+ spl_ptr_llist *llist = object->llist;
+
+ spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, object->flags TSRMLS_CC);
+}
+/* }}} */
+
+static int spl_dllist_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+ spl_ptr_llist_element *element = iterator->traverse_pointer;
+
+ return (element != NULL ? SUCCESS : FAILURE);
+}
+/* }}} */
+
+static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+ spl_ptr_llist_element *element = iterator->traverse_pointer;
+
+ if (element == NULL || element->data == NULL) {
+ *data = NULL;
+ } else {
+ *data = (zval **)&element->data;
+ }
+}
+/* }}} */
+
+static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+
+ *int_key = (ulong) iterator->traverse_position;
+ return HASH_KEY_IS_LONG;
+}
+/* }}} */
+
+static void spl_dllist_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator = (spl_dllist_it *)iter;
+ spl_dllist_object *object = iterator->object;
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+
+ spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, object->flags TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int SplDoublyLinkedList::key() U
+ Return current array key */
+SPL_METHOD(SplDoublyLinkedList, key)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->traverse_position);
+}
+/* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::prev() U
+ Move to next entry */
+SPL_METHOD(SplDoublyLinkedList, prev)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::next() U
+ Move to next entry */
+SPL_METHOD(SplDoublyLinkedList, next)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool SplDoublyLinkedList::valid() U
+ Check whether the datastructure contains more entries */
+SPL_METHOD(SplDoublyLinkedList, valid)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(intern->traverse_pointer != NULL);
+}
+/* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::rewind() U
+ Rewind the datastructure back to the start */
+SPL_METHOD(SplDoublyLinkedList, rewind)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto mixed|NULL SplDoublyLinkedList::current() U
+ Return current datastructure entry */
+SPL_METHOD(SplDoublyLinkedList, current)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_ptr_llist_element *element = intern->traverse_pointer;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (element == NULL || element->data == NULL) {
+ RETURN_NULL();
+ } else {
+ zval *data = (zval *)element->data;
+ RETURN_ZVAL(data, 1, 0);
+ }
+}
+/* }}} */
+/* {{{ proto string SplDoublyLinkedList::serialize()
+ Serializes storage */
+SPL_METHOD(SplDoublyLinkedList, serialize)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ smart_str buf = {0};
+ spl_ptr_llist_element *current = intern->llist->head, *next;
+ zval *flags;
+ php_serialize_data_t var_hash;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+
+ /* flags */
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, intern->flags);
+ php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
+ zval_ptr_dtor(&flags);
+
+ /* elements */
+ while (current) {
+ smart_str_appendc(&buf, ':');
+ next = current->next;
+
+ php_var_serialize(&buf, (zval **)&current->data, &var_hash TSRMLS_CC);
+
+ current = next;
+ }
+
+ smart_str_0(&buf);
+
+ /* done */
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ if (buf.c) {
+ RETURN_STRINGL(buf.c, buf.len, 0);
+ } else {
+ RETURN_NULL();
+ }
+
+} /* }}} */
+
+/* {{{ proto void SplDoublyLinkedList::unserialize(string serialized)
+ Unserializes storage */
+SPL_METHOD(SplDoublyLinkedList, unserialize)
+{
+ spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *flags, *elem;
+ char *buf;
+ int buf_len;
+ const unsigned char *p, *s;
+ php_unserialize_data_t var_hash;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+ return;
+ }
+
+ if (buf_len == 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialized string cannot be empty");
+ return;
+ }
+
+ s = p = (const unsigned char*)buf;
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+
+ /* flags */
+ ALLOC_INIT_ZVAL(flags);
+ if (!php_var_unserialize(&flags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(flags) != IS_LONG) {
+ zval_ptr_dtor(&flags);
+ goto error;
+ }
+ intern->flags = Z_LVAL_P(flags);
+ zval_ptr_dtor(&flags);
+
+ /* elements */
+ while(*p == ':') {
+ ++p;
+ ALLOC_INIT_ZVAL(elem);
+ if (!php_var_unserialize(&elem, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&elem);
+ goto error;
+ }
+
+ spl_ptr_llist_push(intern->llist, elem TSRMLS_CC);
+ }
+
+ if (*p != '\0') {
+ goto error;
+ }
+
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ return;
+
+error:
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ return;
+
+} /* }}} */
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_dllist_it_funcs = {
+ spl_dllist_it_dtor,
+ spl_dllist_it_valid,
+ spl_dllist_it_get_current_data,
+ spl_dllist_it_get_current_key,
+ spl_dllist_it_move_forward,
+ spl_dllist_it_rewind
+};
+
+zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
+{
+ spl_dllist_it *iterator;
+ spl_dllist_object *dllist_object = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (by_ref) {
+ zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ Z_ADDREF_P(object);
+
+ iterator = emalloc(sizeof(spl_dllist_it));
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_dllist_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
+ iterator->traverse_position = dllist_object->traverse_position;
+ iterator->traverse_pointer = dllist_object->traverse_pointer;
+ iterator->flags = dllist_object->flags & SPL_DLLIST_IT_MASK;
+ iterator->object = dllist_object;
+
+ SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer);
+
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+/* Function/Class/Method definitions */
+ZEND_BEGIN_ARG_INFO(arginfo_dllist_setiteratormode, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_dllist_push, 0)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetGet, 0, 0, 1)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetSet, 0, 0, 2)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_dllist_void, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_dllist_serialized, 0)
+ ZEND_ARG_INFO(0, serialized)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_SplQueue[] = {
+ SPL_MA(SplQueue, enqueue, SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC)
+ SPL_MA(SplQueue, dequeue, SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = {
+ SPL_ME(SplDoublyLinkedList, pop, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, unshift, arginfo_dllist_push, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, top, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, bottom, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, isEmpty, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ /* Countable */
+ SPL_ME(SplDoublyLinkedList, count, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ /* ArrayAccess */
+ SPL_ME(SplDoublyLinkedList, offsetExists, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, offsetGet, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, offsetSet, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, offsetUnset, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC)
+ /* Iterator */
+ SPL_ME(SplDoublyLinkedList, rewind, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, current, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, key, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, next, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, prev, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, valid, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ /* Serializable */
+ SPL_ME(SplDoublyLinkedList, unserialize, arginfo_dllist_serialized, ZEND_ACC_PUBLIC)
+ SPL_ME(SplDoublyLinkedList, serialize, arginfo_dllist_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */
+{
+ REGISTER_SPL_STD_CLASS_EX(SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplDoublyLinkedList);
+ memcpy(&spl_handler_SplDoublyLinkedList, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone;
+ spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements;
+ spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info;
+
+ REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO", SPL_DLLIST_IT_LIFO);
+ REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO", 0);
+ REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE",SPL_DLLIST_IT_DELETE);
+ REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP", 0);
+
+ REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Iterator);
+ REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Countable);
+ REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, ArrayAccess);
+ REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Serializable);
+
+ spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator;
+
+ REGISTER_SPL_SUB_CLASS_EX(SplQueue, SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplQueue);
+ REGISTER_SPL_SUB_CLASS_EX(SplStack, SplDoublyLinkedList, spl_dllist_object_new, NULL);
+
+ spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator;
+ spl_ce_SplStack->get_iterator = spl_dllist_get_iterator;
+
+ return SUCCESS;
+}
+/* }}} */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_dllist.h b/ext/spl/spl_dllist.h
new file mode 100644
index 0000000..8615f74
--- /dev/null
+++ b/ext/spl/spl_dllist.h
@@ -0,0 +1,42 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_DLLIST_H
+#define SPL_DLLIST_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList;
+extern PHPAPI zend_class_entry *spl_ce_SplQueue;
+extern PHPAPI zend_class_entry *spl_ce_SplStack;
+
+PHP_MINIT_FUNCTION(spl_dllist);
+
+#endif /* SPL_DLLIST_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c
new file mode 100644
index 0000000..ea2349f
--- /dev/null
+++ b/ext/spl/spl_engine.c
@@ -0,0 +1,70 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_interfaces.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+
+#include "spl_array.h"
+
+/* {{{ spl_instantiate */
+PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC)
+{
+ if (alloc) {
+ ALLOC_ZVAL(*object);
+ }
+ object_init_ex(*object, pce);
+ Z_SET_REFCOUNT_PP(object, 1);
+ Z_SET_ISREF_PP(object); /* check if this can be hold always */
+}
+/* }}} */
+
+PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC) /* {{{ */
+{
+ switch (Z_TYPE_P(offset)) {
+ case IS_STRING:
+ ZEND_HANDLE_NUMERIC(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, idx);
+ break;
+ case IS_DOUBLE:
+ return (long)Z_DVAL_P(offset);
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ return Z_LVAL_P(offset);
+ }
+ return -1;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h
new file mode 100644
index 0000000..103a5c4
--- /dev/null
+++ b/ext/spl/spl_engine.h
@@ -0,0 +1,61 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_ENGINE_H
+#define SPL_ENGINE_H
+
+#include "php.h"
+#include "php_spl.h"
+#include "zend_interfaces.h"
+
+PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC);
+
+PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC);
+
+/* {{{ spl_instantiate_arg_ex1 */
+static inline int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC)
+{
+ spl_instantiate(pce, retval, alloc TSRMLS_CC);
+
+ zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), NULL, 1, arg1, NULL TSRMLS_CC);
+ return 0;
+}
+/* }}} */
+
+/* {{{ spl_instantiate_arg_ex2 */
+static inline int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC)
+{
+ spl_instantiate(pce, retval, alloc TSRMLS_CC);
+
+ zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), NULL, 2, arg1, arg2 TSRMLS_CC);
+ return 0;
+}
+/* }}} */
+
+#endif /* SPL_ENGINE_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_exceptions.c b/ext/spl/spl_exceptions.c
new file mode 100644
index 0000000..d905070
--- /dev/null
+++ b/ext/spl/spl_exceptions.c
@@ -0,0 +1,81 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_exceptions.h"
+
+PHPAPI zend_class_entry *spl_ce_LogicException;
+PHPAPI zend_class_entry *spl_ce_BadFunctionCallException;
+PHPAPI zend_class_entry *spl_ce_BadMethodCallException;
+PHPAPI zend_class_entry *spl_ce_DomainException;
+PHPAPI zend_class_entry *spl_ce_InvalidArgumentException;
+PHPAPI zend_class_entry *spl_ce_LengthException;
+PHPAPI zend_class_entry *spl_ce_OutOfRangeException;
+PHPAPI zend_class_entry *spl_ce_RuntimeException;
+PHPAPI zend_class_entry *spl_ce_OutOfBoundsException;
+PHPAPI zend_class_entry *spl_ce_OverflowException;
+PHPAPI zend_class_entry *spl_ce_RangeException;
+PHPAPI zend_class_entry *spl_ce_UnderflowException;
+PHPAPI zend_class_entry *spl_ce_UnexpectedValueException;
+
+#define spl_ce_Exception zend_exception_get_default(TSRMLS_C)
+
+/* {{{ PHP_MINIT_FUNCTION(spl_exceptions) */
+PHP_MINIT_FUNCTION(spl_exceptions)
+{
+ REGISTER_SPL_SUB_CLASS_EX(LogicException, Exception, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(BadFunctionCallException, LogicException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(BadMethodCallException, BadFunctionCallException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(DomainException, LogicException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(InvalidArgumentException, LogicException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(LengthException, LogicException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(OutOfRangeException, LogicException, NULL, NULL);
+
+ REGISTER_SPL_SUB_CLASS_EX(RuntimeException, Exception, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(OutOfBoundsException, RuntimeException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(OverflowException, RuntimeException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(RangeException, RuntimeException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(UnderflowException, RuntimeException, NULL, NULL);
+ REGISTER_SPL_SUB_CLASS_EX(UnexpectedValueException, RuntimeException, NULL, NULL);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_exceptions.h b/ext/spl/spl_exceptions.h
new file mode 100644
index 0000000..e4e7f27
--- /dev/null
+++ b/ext/spl/spl_exceptions.h
@@ -0,0 +1,53 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_EXCEPTIONS_H
+#define SPL_EXCEPTIONS_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_LogicException;
+extern PHPAPI zend_class_entry *spl_ce_BadFunctionCallException;
+extern PHPAPI zend_class_entry *spl_ce_BadMethodCallException;
+extern PHPAPI zend_class_entry *spl_ce_DomainException;
+extern PHPAPI zend_class_entry *spl_ce_InvalidArgumentException;
+extern PHPAPI zend_class_entry *spl_ce_LengthException;
+extern PHPAPI zend_class_entry *spl_ce_OutOfRangeException;
+
+extern PHPAPI zend_class_entry *spl_ce_RuntimeException;
+extern PHPAPI zend_class_entry *spl_ce_OutOfBoundsException;
+extern PHPAPI zend_class_entry *spl_ce_OverflowException;
+extern PHPAPI zend_class_entry *spl_ce_RangeException;
+extern PHPAPI zend_class_entry *spl_ce_UnderflowException;
+extern PHPAPI zend_class_entry *spl_ce_UnexpectedValueException;
+
+PHP_MINIT_FUNCTION(spl_exceptions);
+
+#endif /* SPL_EXCEPTIONS_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c
new file mode 100644
index 0000000..ebc4e34
--- /dev/null
+++ b/ext/spl/spl_fixedarray.c
@@ -0,0 +1,1140 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Antony Dovgal <tony@daylessday.org> |
+ | Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_exceptions.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_fixedarray.h"
+#include "spl_exceptions.h"
+#include "spl_iterators.h"
+
+zend_object_handlers spl_handler_SplFixedArray;
+PHPAPI zend_class_entry *spl_ce_SplFixedArray;
+
+#ifdef COMPILE_DL_SPL_FIXEDARRAY
+ZEND_GET_MODULE(spl_fixedarray)
+#endif
+
+typedef struct _spl_fixedarray { /* {{{ */
+ long size;
+ zval **elements;
+} spl_fixedarray;
+/* }}} */
+
+typedef struct _spl_fixedarray_object { /* {{{ */
+ zend_object std;
+ spl_fixedarray *array;
+ zval *retval;
+ zend_function *fptr_offset_get;
+ zend_function *fptr_offset_set;
+ zend_function *fptr_offset_has;
+ zend_function *fptr_offset_del;
+ zend_function *fptr_count;
+ int current;
+ int flags;
+ zend_class_entry *ce_get_iterator;
+} spl_fixedarray_object;
+/* }}} */
+
+typedef struct _spl_fixedarray_it { /* {{{ */
+ zend_user_iterator intern;
+ spl_fixedarray_object *object;
+} spl_fixedarray_it;
+/* }}} */
+
+#define SPL_FIXEDARRAY_OVERLOADED_REWIND 0x0001
+#define SPL_FIXEDARRAY_OVERLOADED_VALID 0x0002
+#define SPL_FIXEDARRAY_OVERLOADED_KEY 0x0004
+#define SPL_FIXEDARRAY_OVERLOADED_CURRENT 0x0008
+#define SPL_FIXEDARRAY_OVERLOADED_NEXT 0x0010
+
+static void spl_fixedarray_init(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */
+{
+ if (size > 0) {
+ array->size = 0; /* reset size in case ecalloc() fails */
+ array->elements = ecalloc(size, sizeof(zval *));
+ array->size = size;
+ } else {
+ array->elements = NULL;
+ array->size = 0;
+ }
+}
+/* }}} */
+
+static void spl_fixedarray_resize(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */
+{
+ if (size == array->size) {
+ /* nothing to do */
+ return;
+ }
+
+ /* first initialization */
+ if (array->size == 0) {
+ spl_fixedarray_init(array, size TSRMLS_CC);
+ return;
+ }
+
+ /* clearing the array */
+ if (size == 0) {
+ long i;
+
+ for (i = 0; i < array->size; i++) {
+ if (array->elements[i]) {
+ zval_ptr_dtor(&(array->elements[i]));
+ }
+ }
+
+ if (array->elements) {
+ efree(array->elements);
+ array->elements = NULL;
+ }
+ } else if (size > array->size) {
+ array->elements = erealloc(array->elements, sizeof(zval *) * size);
+ memset(array->elements + array->size, '\0', sizeof(zval *) * (size - array->size));
+ } else { /* size < array->size */
+ long i;
+
+ for (i = size; i < array->size; i++) {
+ if (array->elements[i]) {
+ zval_ptr_dtor(&(array->elements[i]));
+ }
+ }
+ array->elements = erealloc(array->elements, sizeof(zval *) * size);
+ }
+
+ array->size = size;
+}
+/* }}} */
+
+static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from TSRMLS_DC) /* {{{ */
+{
+ int i;
+ for (i = 0; i < from->size; i++) {
+ if (from->elements[i]) {
+ Z_ADDREF_P(from->elements[i]);
+ to->elements[i] = from->elements[i];
+ } else {
+ to->elements[i] = NULL;
+ }
+ }
+}
+/* }}} */
+
+static HashTable* spl_fixedarray_object_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{{ */
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ HashTable *ht = zend_std_get_properties(obj TSRMLS_CC);
+
+ if (intern->array) {
+ *table = intern->array->elements;
+ *n = intern->array->size;
+ } else {
+ *table = NULL;
+ *n = 0;
+ }
+
+ return ht;
+}
+/* }}}} */
+
+static HashTable* spl_fixedarray_object_get_properties(zval *obj TSRMLS_DC) /* {{{{ */
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ HashTable *ht = zend_std_get_properties(obj TSRMLS_CC);
+ int i = 0;
+
+ if (intern->array) {
+ int j = zend_hash_num_elements(ht);
+
+ for (i = 0; i < intern->array->size; i++) {
+ if (intern->array->elements[i]) {
+ zend_hash_index_update(ht, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);
+ Z_ADDREF_P(intern->array->elements[i]);
+ } else {
+ zend_hash_index_update(ht, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);
+ Z_ADDREF_P(EG(uninitialized_zval_ptr));
+ }
+ }
+ if (j > intern->array->size) {
+ for (i = intern->array->size; i < j; ++i) {
+ zend_hash_index_del(ht, i);
+ }
+ }
+ }
+
+ return ht;
+}
+/* }}}} */
+
+static void spl_fixedarray_object_free_storage(void *object TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object *)object;
+ long i;
+
+ if (intern->array) {
+ for (i = 0; i < intern->array->size; i++) {
+ if (intern->array->elements[i]) {
+ zval_ptr_dtor(&(intern->array->elements[i]));
+ }
+ }
+
+ if (intern->array->size > 0 && intern->array->elements) {
+ efree(intern->array->elements);
+ }
+ efree(intern->array);
+ }
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+ zval_ptr_dtor(&intern->retval);
+
+ efree(object);
+}
+/* }}} */
+
+zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
+
+static zend_object_value spl_fixedarray_object_new_ex(zend_class_entry *class_type, spl_fixedarray_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */
+{
+ zend_object_value retval;
+ spl_fixedarray_object *intern;
+ zend_class_entry *parent = class_type;
+ int inherited = 0;
+
+ intern = ecalloc(1, sizeof(spl_fixedarray_object));
+ *obj = intern;
+ ALLOC_INIT_ZVAL(intern->retval);
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ intern->current = 0;
+ intern->flags = 0;
+
+ if (orig && clone_orig) {
+ spl_fixedarray_object *other = (spl_fixedarray_object*)zend_object_store_get_object(orig TSRMLS_CC);
+ intern->ce_get_iterator = other->ce_get_iterator;
+ if (!other->array) {
+ /* leave a empty object, will be dtor later by CLONE handler */
+ zend_throw_exception(spl_ce_RuntimeException, "The instance wasn't initialized properly", 0 TSRMLS_CC);
+ } else {
+ intern->array = emalloc(sizeof(spl_fixedarray));
+ spl_fixedarray_init(intern->array, other->array->size TSRMLS_CC);
+ spl_fixedarray_copy(intern->array, other->array TSRMLS_CC);
+ }
+ }
+
+ while (parent) {
+ if (parent == spl_ce_SplFixedArray) {
+ retval.handlers = &spl_handler_SplFixedArray;
+ class_type->get_iterator = spl_fixedarray_get_iterator;
+ break;
+ }
+
+ parent = parent->parent;
+ inherited = 1;
+ }
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_fixedarray_object_free_storage, NULL TSRMLS_CC);
+
+ if (!parent) { /* this must never happen */
+ php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
+ }
+ if (!class_type->iterator_funcs.zf_current) {
+ zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
+ zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
+ zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
+ zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
+ zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
+ }
+ if (inherited) {
+ if (class_type->iterator_funcs.zf_rewind->common.scope != parent) {
+ intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
+ }
+ if (class_type->iterator_funcs.zf_valid->common.scope != parent) {
+ intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
+ }
+ if (class_type->iterator_funcs.zf_key->common.scope != parent) {
+ intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
+ }
+ if (class_type->iterator_funcs.zf_current->common.scope != parent) {
+ intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
+ }
+ if (class_type->iterator_funcs.zf_next->common.scope != parent) {
+ intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
+ }
+
+ zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
+ if (intern->fptr_offset_get->common.scope == parent) {
+ intern->fptr_offset_get = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
+ if (intern->fptr_offset_set->common.scope == parent) {
+ intern->fptr_offset_set = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
+ if (intern->fptr_offset_has->common.scope == parent) {
+ intern->fptr_offset_has = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
+ if (intern->fptr_offset_del->common.scope == parent) {
+ intern->fptr_offset_del = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
+ if (intern->fptr_count->common.scope == parent) {
+ intern->fptr_count = NULL;
+ }
+ }
+
+ return retval;
+}
+/* }}} */
+
+static zend_object_value spl_fixedarray_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *tmp;
+ return spl_fixedarray_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static zend_object_value spl_fixedarray_object_clone(zval *zobject TSRMLS_DC) /* {{{ */
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_fixedarray_object *intern;
+
+ old_object = zend_objects_get_address(zobject TSRMLS_CC);
+ new_obj_val = spl_fixedarray_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
+ new_object = &intern->std;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ return new_obj_val;
+}
+/* }}} */
+
+static inline zval **spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */
+{
+ long index;
+
+ /* we have to return NULL on error here to avoid memleak because of
+ * ZE duplicating uninitialized_zval_ptr */
+ if (!offset) {
+ zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ index = spl_offset_convert_to_long(offset TSRMLS_CC);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+
+ if (index < 0 || intern->array == NULL || index >= intern->array->size) {
+ zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
+ return NULL;
+ } else if(!intern->array->elements[index]) {
+ return NULL;
+ } else {
+ return &intern->array->elements[index];
+ }
+}
+/* }}} */
+
+static zval *spl_fixedarray_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern;
+ zval **retval;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_offset_get) {
+ zval *rv;
+ if (!offset) {
+ ALLOC_INIT_ZVAL(offset);
+ } else {
+ SEPARATE_ARG_IF_REF(offset);
+ }
+ zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", &rv, offset);
+ zval_ptr_dtor(&offset);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ return intern->retval;
+ }
+ return EG(uninitialized_zval_ptr);
+ }
+
+ retval = spl_fixedarray_object_read_dimension_helper(intern, offset TSRMLS_CC);
+ if (retval) {
+ return *retval;
+ }
+ return NULL;
+}
+/* }}} */
+
+static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value TSRMLS_DC) /* {{{ */
+{
+ long index;
+
+ if (!offset) {
+ /* '$array[] = value' syntax is not supported */
+ zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
+ return;
+ }
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ index = spl_offset_convert_to_long(offset TSRMLS_CC);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+
+ if (index < 0 || intern->array == NULL || index >= intern->array->size) {
+ zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
+ return;
+ } else {
+ if (intern->array->elements[index]) {
+ zval_ptr_dtor(&(intern->array->elements[index]));
+ }
+ SEPARATE_ARG_IF_REF(value);
+ intern->array->elements[index] = value;
+ }
+}
+/* }}} */
+
+static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_offset_set) {
+ if (!offset) {
+ ALLOC_INIT_ZVAL(offset);
+ } else {
+ SEPARATE_ARG_IF_REF(offset);
+ }
+ SEPARATE_ARG_IF_REF(value);
+ zend_call_method_with_2_params(&object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
+ zval_ptr_dtor(&value);
+ zval_ptr_dtor(&offset);
+ return;
+ }
+
+ spl_fixedarray_object_write_dimension_helper(intern, offset, value TSRMLS_CC);
+}
+/* }}} */
+
+static inline void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */
+{
+ long index;
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ index = spl_offset_convert_to_long(offset TSRMLS_CC);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+
+ if (index < 0 || intern->array == NULL || index >= intern->array->size) {
+ zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC);
+ return;
+ } else {
+ if (intern->array->elements[index]) {
+ zval_ptr_dtor(&(intern->array->elements[index]));
+ }
+ intern->array->elements[index] = NULL;
+ }
+}
+/* }}} */
+
+static void spl_fixedarray_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_offset_del) {
+ SEPARATE_ARG_IF_REF(offset);
+ zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
+ zval_ptr_dtor(&offset);
+ return;
+ }
+
+ spl_fixedarray_object_unset_dimension_helper(intern, offset TSRMLS_CC);
+
+}
+/* }}} */
+
+static inline int spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
+{
+ long index;
+ int retval;
+
+ if (Z_TYPE_P(offset) != IS_LONG) {
+ index = spl_offset_convert_to_long(offset TSRMLS_CC);
+ } else {
+ index = Z_LVAL_P(offset);
+ }
+
+ if (index < 0 || intern->array == NULL || index >= intern->array->size) {
+ retval = 0;
+ } else {
+ if (!intern->array->elements[index]) {
+ retval = 0;
+ } else if (check_empty) {
+ if (zend_is_true(intern->array->elements[index])) {
+ retval = 1;
+ } else {
+ retval = 0;
+ }
+ } else { /* != NULL and !check_empty */
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
+/* }}} */
+
+static int spl_fixedarray_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_offset_get) {
+ zval *rv;
+ SEPARATE_ARG_IF_REF(offset);
+ zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
+ zval_ptr_dtor(&offset);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ return zend_is_true(intern->retval);
+ }
+ return 0;
+ }
+
+ return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty TSRMLS_CC);
+}
+/* }}} */
+
+static int spl_fixedarray_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_object *intern;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+ if (intern->fptr_count) {
+ zval *rv;
+ zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ convert_to_long(intern->retval);
+ *count = (long) Z_LVAL_P(intern->retval);
+ return SUCCESS;
+ }
+ } else if (intern->array) {
+ *count = intern->array->size;
+ return SUCCESS;
+ }
+
+ *count = 0;
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ proto void SplFixedArray::__construct([int size])
+*/
+SPL_METHOD(SplFixedArray, __construct)
+{
+ zval *object = getThis();
+ spl_fixedarray_object *intern;
+ long size = 0;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size)) {
+ return;
+ }
+
+ if (size < 0) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero");
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->array) {
+ /* called __construct() twice, bail out */
+ return;
+ }
+
+ intern->array = emalloc(sizeof(spl_fixedarray));
+ spl_fixedarray_init(intern->array, size TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int SplFixedArray::count(void)
+*/
+SPL_METHOD(SplFixedArray, count)
+{
+ zval *object = getThis();
+ spl_fixedarray_object *intern;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+ if (intern->array) {
+ RETURN_LONG(intern->array->size);
+ }
+ RETURN_LONG(0);
+}
+/* }}} */
+
+/* {{{ proto object SplFixedArray::toArray()
+*/
+SPL_METHOD(SplFixedArray, toArray)
+{
+ spl_fixedarray_object *intern;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ array_init(return_value);
+ if (intern->array) {
+ int i = 0;
+ for (; i < intern->array->size; i++) {
+ if (intern->array->elements[i]) {
+ zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);
+ Z_ADDREF_P(intern->array->elements[i]);
+ } else {
+ zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);
+ Z_ADDREF_P(EG(uninitialized_zval_ptr));
+ }
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes])
+*/
+SPL_METHOD(SplFixedArray, fromArray)
+{
+ zval *data;
+ spl_fixedarray *array;
+ spl_fixedarray_object *intern;
+ int num;
+ zend_bool save_indexes = 1;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &data, &save_indexes)) {
+ return;
+ }
+
+ array = ecalloc(1, sizeof(*array));
+ num = zend_hash_num_elements(Z_ARRVAL_P(data));
+
+ if (num > 0 && save_indexes) {
+ zval **element, *value;
+ char *str_index;
+ ulong num_index, max_index = 0;
+ long tmp;
+
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
+ zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
+ zend_hash_move_forward(Z_ARRVAL_P(data))
+ ) {
+ if (zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0) != HASH_KEY_IS_LONG || (long)num_index < 0) {
+ efree(array);
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array must contain only positive integer keys");
+ return;
+ }
+
+ if (num_index > max_index) {
+ max_index = num_index;
+ }
+ }
+
+ tmp = max_index + 1;
+ if (tmp <= 0) {
+ efree(array);
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "integer overflow detected");
+ return;
+ }
+ spl_fixedarray_init(array, tmp TSRMLS_CC);
+
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
+ zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
+ zend_hash_move_forward(Z_ARRVAL_P(data))
+ ) {
+
+ zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0);
+ value = *element;
+
+ SEPARATE_ARG_IF_REF(value);
+ array->elements[num_index] = value;
+ }
+
+ } else if (num > 0 && !save_indexes) {
+ zval **element, *value;
+ long i = 0;
+
+ spl_fixedarray_init(array, num TSRMLS_CC);
+
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
+ zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
+ zend_hash_move_forward(Z_ARRVAL_P(data))
+ ) {
+
+ value = *element;
+
+ SEPARATE_ARG_IF_REF(value);
+ array->elements[i] = value;
+ i++;
+ }
+ } else {
+ spl_fixedarray_init(array, 0 TSRMLS_CC);
+ }
+
+ object_init_ex(return_value, spl_ce_SplFixedArray);
+ Z_TYPE_P(return_value) = IS_OBJECT;
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(return_value TSRMLS_CC);
+ intern->array = array;
+}
+/* }}} */
+
+/* {{{ proto int SplFixedArray::getSize(void)
+*/
+SPL_METHOD(SplFixedArray, getSize)
+{
+ zval *object = getThis();
+ spl_fixedarray_object *intern;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+ if (intern->array) {
+ RETURN_LONG(intern->array->size);
+ }
+ RETURN_LONG(0);
+}
+/* }}} */
+
+/* {{{ proto bool SplFixedArray::setSize(int size)
+*/
+SPL_METHOD(SplFixedArray, setSize)
+{
+ zval *object = getThis();
+ spl_fixedarray_object *intern;
+ long size;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size)) {
+ return;
+ }
+
+ if (size < 0) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero");
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
+ if (!intern->array) {
+ intern->array = ecalloc(1, sizeof(spl_fixedarray));
+ }
+
+ spl_fixedarray_resize(intern->array, size TSRMLS_CC);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool SplFixedArray::offsetExists(mixed $index) U
+ Returns whether the requested $index exists. */
+SPL_METHOD(SplFixedArray, offsetExists)
+{
+ zval *zindex;
+ spl_fixedarray_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0 TSRMLS_CC));
+} /* }}} */
+
+/* {{{ proto mixed SplFixedArray::offsetGet(mixed $index) U
+ Returns the value at the specified $index. */
+SPL_METHOD(SplFixedArray, offsetGet)
+{
+ zval *zindex, **value_pp;
+ spl_fixedarray_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
+
+ if (value_pp) {
+ RETURN_ZVAL(*value_pp, 1, 0);
+ }
+ RETURN_NULL();
+} /* }}} */
+
+/* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval) U
+ Sets the value at the specified $index to $newval. */
+SPL_METHOD(SplFixedArray, offsetSet)
+{
+ zval *zindex, *value;
+ spl_fixedarray_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_fixedarray_object_write_dimension_helper(intern, zindex, value TSRMLS_CC);
+
+} /* }}} */
+
+/* {{{ proto void SplFixedArray::offsetUnset(mixed $index) U
+ Unsets the value at the specified $index. */
+SPL_METHOD(SplFixedArray, offsetUnset)
+{
+ zval *zindex;
+ spl_fixedarray_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_fixedarray_object_unset_dimension_helper(intern, zindex TSRMLS_CC);
+
+} /* }}} */
+
+static void spl_fixedarray_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ zval_ptr_dtor((zval**)&iterator->intern.it.data);
+
+ efree(iterator);
+}
+/* }}} */
+
+static void spl_fixedarray_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+ spl_fixedarray_object *intern = iterator->object;
+
+ if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) {
+ zend_user_it_rewind(iter TSRMLS_CC);
+ } else {
+ iterator->object->current = 0;
+ }
+}
+/* }}} */
+
+static int spl_fixedarray_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+ spl_fixedarray_object *intern = iterator->object;
+
+ if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) {
+ return zend_user_it_valid(iter TSRMLS_CC);
+ }
+
+ if (iterator->object->current >= 0 && iterator->object->array && iterator->object->current < iterator->object->array->size) {
+ return SUCCESS;
+ }
+
+ return FAILURE;
+}
+/* }}} */
+
+static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
+{
+ zval *zindex;
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+ spl_fixedarray_object *intern = iterator->object;
+
+ if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) {
+ zend_user_it_get_current_data(iter, data TSRMLS_CC);
+ } else {
+ ALLOC_INIT_ZVAL(zindex);
+ ZVAL_LONG(zindex, iterator->object->current);
+
+ *data = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
+
+ if (*data == NULL) {
+ *data = &EG(uninitialized_zval_ptr);
+ }
+
+ zval_ptr_dtor(&zindex);
+ }
+}
+/* }}} */
+
+static int spl_fixedarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+ spl_fixedarray_object *intern = iterator->object;
+
+ if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
+ return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
+ } else {
+ *int_key = (ulong) iterator->object->current;
+ return HASH_KEY_IS_LONG;
+ }
+
+}
+/* }}} */
+
+static void spl_fixedarray_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
+ spl_fixedarray_object *intern = iterator->object;
+
+ if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) {
+ zend_user_it_move_forward(iter TSRMLS_CC);
+ } else {
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ iterator->object->current++;
+ }
+}
+/* }}} */
+
+/* {{{ proto int SplFixedArray::key() U
+ Return current array key */
+SPL_METHOD(SplFixedArray, key)
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->current);
+}
+/* }}} */
+
+/* {{{ proto void SplFixedArray::next() U
+ Move to next entry */
+SPL_METHOD(SplFixedArray, next)
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern->current++;
+}
+/* }}} */
+
+/* {{{ proto bool SplFixedArray::valid() U
+ Check whether the datastructure contains more entries */
+SPL_METHOD(SplFixedArray, valid)
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(intern->current >= 0 && intern->array && intern->current < intern->array->size);
+}
+/* }}} */
+
+/* {{{ proto void SplFixedArray::rewind() U
+ Rewind the datastructure back to the start */
+SPL_METHOD(SplFixedArray, rewind)
+{
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern->current = 0;
+}
+/* }}} */
+
+/* {{{ proto mixed|NULL SplFixedArray::current() U
+ Return current datastructure entry */
+SPL_METHOD(SplFixedArray, current)
+{
+ zval *zindex, **value_pp;
+ spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ ALLOC_INIT_ZVAL(zindex);
+ ZVAL_LONG(zindex, intern->current);
+
+ value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
+
+ zval_ptr_dtor(&zindex);
+
+ if (value_pp) {
+ RETURN_ZVAL(*value_pp, 1, 0);
+ }
+ RETURN_NULL();
+}
+/* }}} */
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_fixedarray_it_funcs = {
+ spl_fixedarray_it_dtor,
+ spl_fixedarray_it_valid,
+ spl_fixedarray_it_get_current_data,
+ spl_fixedarray_it_get_current_key,
+ spl_fixedarray_it_move_forward,
+ spl_fixedarray_it_rewind
+};
+
+zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
+{
+ spl_fixedarray_it *iterator;
+ spl_fixedarray_object *fixedarray_object = (spl_fixedarray_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (by_ref) {
+ zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ Z_ADDREF_P(object);
+
+ iterator = emalloc(sizeof(spl_fixedarray_it));
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_fixedarray_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
+ iterator->object = fixedarray_object;
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0)
+ ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1)
+ ZEND_ARG_INFO(0, data)
+ ZEND_ARG_INFO(0, save_indexes)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0)
+ZEND_END_ARG_INFO()
+
+static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */
+ SPL_ME(SplFixedArray, __construct, arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, count, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, toArray, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, fromArray, arginfo_fixedarray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ SPL_ME(SplFixedArray, getSize, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, setSize, arginfo_fixedarray_setSize, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, offsetExists, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, offsetGet, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, offsetSet, arginfo_fixedarray_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, offsetUnset, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, rewind, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, current, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, key, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, next, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFixedArray, valid, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION */
+PHP_MINIT_FUNCTION(spl_fixedarray)
+{
+ REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray);
+ memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone;
+ spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension;
+ spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension;
+ spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension;
+ spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension;
+ spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements;
+ spl_handler_SplFixedArray.get_properties = spl_fixedarray_object_get_properties;
+ spl_handler_SplFixedArray.get_gc = spl_fixedarray_object_get_gc;
+
+ REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator);
+ REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess);
+ REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable);
+
+ spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator;
+
+ return SUCCESS;
+}
+/* }}} */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_fixedarray.h b/ext/spl/spl_fixedarray.h
new file mode 100644
index 0000000..8f1b8df
--- /dev/null
+++ b/ext/spl/spl_fixedarray.h
@@ -0,0 +1,38 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Antony Dovgal <tony@daylessday.org> |
+ | Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef SPL_FIXEDARRAY_H
+#define SPL_FIXEDARRAY_H
+
+extern PHPAPI zend_class_entry *spl_ce_SplFixedArray;
+
+PHP_MINIT_FUNCTION(spl_fixedarray);
+
+#endif /* SPL_FIXEDARRAY_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c
new file mode 100644
index 0000000..7f17d5e
--- /dev/null
+++ b/ext/spl/spl_functions.c
@@ -0,0 +1,153 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_spl.h"
+
+/* {{{ spl_register_interface */
+void spl_register_interface(zend_class_entry ** ppce, char * class_name, const zend_function_entry * functions TSRMLS_DC)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), functions);
+ *ppce = zend_register_internal_interface(&ce TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_register_std_class */
+PHPAPI void spl_register_std_class(zend_class_entry ** ppce, char * class_name, void * obj_ctor, const zend_function_entry * function_list TSRMLS_DC)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), function_list);
+ *ppce = zend_register_internal_class(&ce TSRMLS_CC);
+
+ /* entries changed by initialize */
+ if (obj_ctor) {
+ (*ppce)->create_object = obj_ctor;
+ }
+}
+/* }}} */
+
+/* {{{ spl_register_sub_class */
+PHPAPI void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, void *obj_ctor, const zend_function_entry * function_list TSRMLS_DC)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), function_list);
+ *ppce = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC);
+
+ /* entries changed by initialize */
+ if (obj_ctor) {
+ (*ppce)->create_object = obj_ctor;
+ } else {
+ (*ppce)->create_object = parent_ce->create_object;
+ }
+}
+/* }}} */
+
+/* {{{ spl_register_property */
+void spl_register_property( zend_class_entry * class_entry, char *prop_name, int prop_name_len, int prop_flags TSRMLS_DC)
+{
+ zend_declare_property_null(class_entry, prop_name, prop_name_len, prop_flags TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_add_class_name */
+void spl_add_class_name(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC)
+{
+ if (!allow || (allow > 0 && pce->ce_flags & ce_flags) || (allow < 0 && !(pce->ce_flags & ce_flags))) {
+ size_t len = pce->name_length;
+ zval *tmp;
+
+ if (zend_hash_find(Z_ARRVAL_P(list), pce->name, len+1, (void*)&tmp) == FAILURE) {
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, pce->name, pce->name_length, 1);
+ zend_hash_add(Z_ARRVAL_P(list), pce->name, len+1, &tmp, sizeof(zval *), NULL);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ spl_add_interfaces */
+void spl_add_interfaces(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC)
+{
+ zend_uint num_interfaces;
+
+ for (num_interfaces = 0; num_interfaces < pce->num_interfaces; num_interfaces++) {
+ spl_add_class_name(list, pce->interfaces[num_interfaces], allow, ce_flags TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ spl_add_traits */
+void spl_add_traits(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC)
+{
+ zend_uint num_traits;
+
+ for (num_traits = 0; num_traits < pce->num_traits; num_traits++) {
+ spl_add_class_name(list, pce->traits[num_traits], allow, ce_flags TSRMLS_CC);
+ }
+}
+/* }}} */
+
+
+/* {{{ spl_add_classes */
+int spl_add_classes(zend_class_entry *pce, zval *list, int sub, int allow, int ce_flags TSRMLS_DC)
+{
+ if (!pce) {
+ return 0;
+ }
+ spl_add_class_name(list, pce, allow, ce_flags TSRMLS_CC);
+ if (sub) {
+ spl_add_interfaces(list, pce, allow, ce_flags TSRMLS_CC);
+ while (pce->parent) {
+ pce = pce->parent;
+ spl_add_classes(pce, list, sub, allow, ce_flags TSRMLS_CC);
+ }
+ }
+ return 0;
+}
+/* }}} */
+
+char * spl_gen_private_prop_name(zend_class_entry *ce, char *prop_name, int prop_len, int *name_len TSRMLS_DC) /* {{{ */
+{
+ char *rv;
+
+ zend_mangle_property_name(&rv, name_len, ce->name, ce->name_length, prop_name, prop_len, 0);
+
+ return rv;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h
new file mode 100644
index 0000000..29ce4a7
--- /dev/null
+++ b/ext/spl/spl_functions.h
@@ -0,0 +1,91 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_FUNCTIONS_H
+#define PHP_FUNCTIONS_H
+
+#include "php.h"
+
+typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type TSRMLS_DC);
+
+#define REGISTER_SPL_STD_CLASS(class_name, obj_ctor) \
+ spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, NULL TSRMLS_CC);
+
+#define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \
+ spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC);
+
+#define REGISTER_SPL_SUB_CLASS_EX(class_name, parent_class_name, obj_ctor, funcs) \
+ spl_register_sub_class(&spl_ce_ ## class_name, spl_ce_ ## parent_class_name, # class_name, obj_ctor, funcs TSRMLS_CC);
+
+#define REGISTER_SPL_INTERFACE(class_name) \
+ spl_register_interface(&spl_ce_ ## class_name, # class_name, spl_funcs_ ## class_name TSRMLS_CC);
+
+#define REGISTER_SPL_IMPLEMENTS(class_name, interface_name) \
+ zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, spl_ce_ ## interface_name);
+
+#define REGISTER_SPL_ITERATOR(class_name) \
+ zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, zend_ce_iterator);
+
+#define REGISTER_SPL_PROPERTY(class_name, prop_name, prop_flags) \
+ spl_register_property(spl_ce_ ## class_name, prop_name, sizeof(prop_name)-1, prop_flags TSRMLS_CC);
+
+#define REGISTER_SPL_CLASS_CONST_LONG(class_name, const_name, value) \
+ zend_declare_class_constant_long(spl_ce_ ## class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
+
+void spl_register_std_class(zend_class_entry ** ppce, char * class_name, create_object_func_t ctor, const zend_function_entry * function_list TSRMLS_DC);
+void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, create_object_func_t ctor, const zend_function_entry * function_list TSRMLS_DC);
+void spl_register_interface(zend_class_entry ** ppce, char * class_name, const zend_function_entry *functions TSRMLS_DC);
+
+void spl_register_property( zend_class_entry * class_entry, char *prop_name, int prop_name_len, int prop_flags TSRMLS_DC);
+
+/* sub: whether to allow subclasses/interfaces
+ allow = 0: allow all classes and interfaces
+ allow > 0: allow all that match and mask ce_flags
+ allow < 0: disallow all that match and mask ce_flags
+ */
+void spl_add_class_name(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC);
+void spl_add_interfaces(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC);
+void spl_add_traits(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC);
+int spl_add_classes(zend_class_entry *pce, zval *list, int sub, int allow, int ce_flags TSRMLS_DC);
+
+/* caller must efree(return) */
+char * spl_gen_private_prop_name(zend_class_entry *ce, char *prop_name, int prop_len, int *name_len TSRMLS_DC);
+
+#define SPL_ME(class_name, function_name, arg_info, flags) \
+ PHP_ME( spl_ ## class_name, function_name, arg_info, flags)
+
+#define SPL_ABSTRACT_ME(class_name, function_name, arg_info) \
+ ZEND_ABSTRACT_ME( spl_ ## class_name, function_name, arg_info)
+
+#define SPL_METHOD(class_name, function_name) \
+ PHP_METHOD(spl_ ## class_name, function_name)
+
+#define SPL_MA(class_name, function_name, alias_class, alias_function, arg_info, flags) \
+ PHP_MALIAS(spl_ ## alias_class, function_name, alias_function, arg_info, flags)
+#endif /* PHP_FUNCTIONS_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c
new file mode 100644
index 0000000..d2de85b
--- /dev/null
+++ b/ext/spl/spl_heap.c
@@ -0,0 +1,1262 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "zend_exceptions.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+#include "spl_heap.h"
+#include "spl_exceptions.h"
+
+#define PTR_HEAP_BLOCK_SIZE 64
+
+#define SPL_HEAP_CORRUPTED 0x00000001
+
+#define SPL_PQUEUE_EXTR_MASK 0x00000003
+#define SPL_PQUEUE_EXTR_BOTH 0x00000003
+#define SPL_PQUEUE_EXTR_DATA 0x00000001
+#define SPL_PQUEUE_EXTR_PRIORITY 0x00000002
+
+zend_object_handlers spl_handler_SplHeap;
+zend_object_handlers spl_handler_SplPriorityQueue;
+
+PHPAPI zend_class_entry *spl_ce_SplHeap;
+PHPAPI zend_class_entry *spl_ce_SplMaxHeap;
+PHPAPI zend_class_entry *spl_ce_SplMinHeap;
+PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
+
+typedef void *spl_ptr_heap_element;
+
+typedef void (*spl_ptr_heap_dtor_func)(spl_ptr_heap_element TSRMLS_DC);
+typedef void (*spl_ptr_heap_ctor_func)(spl_ptr_heap_element TSRMLS_DC);
+typedef int (*spl_ptr_heap_cmp_func)(spl_ptr_heap_element, spl_ptr_heap_element, void* TSRMLS_DC);
+
+typedef struct _spl_ptr_heap {
+ spl_ptr_heap_element *elements;
+ spl_ptr_heap_ctor_func ctor;
+ spl_ptr_heap_dtor_func dtor;
+ spl_ptr_heap_cmp_func cmp;
+ int count;
+ int max_size;
+ int flags;
+} spl_ptr_heap;
+
+typedef struct _spl_heap_object spl_heap_object;
+typedef struct _spl_heap_it spl_heap_it;
+
+struct _spl_heap_object {
+ zend_object std;
+ spl_ptr_heap *heap;
+ zval *retval;
+ int flags;
+ zend_class_entry *ce_get_iterator;
+ zend_function *fptr_cmp;
+ zend_function *fptr_count;
+ HashTable *debug_info;
+};
+
+/* define an overloaded iterator structure */
+struct _spl_heap_it {
+ zend_user_iterator intern;
+ int flags;
+ spl_heap_object *object;
+};
+
+/* {{{ spl_ptr_heap */
+static void spl_ptr_heap_zval_dtor(spl_ptr_heap_element elem TSRMLS_DC) { /* {{{ */
+ if (elem) {
+ zval_ptr_dtor((zval **)&elem);
+ }
+}
+/* }}} */
+
+static void spl_ptr_heap_zval_ctor(spl_ptr_heap_element elem TSRMLS_DC) { /* {{{ */
+ Z_ADDREF_P((zval *)elem);
+}
+/* }}} */
+
+static int spl_ptr_heap_cmp_cb_helper(zval *object, spl_heap_object *heap_object, zval *a, zval *b, long *result TSRMLS_DC) { /* {{{ */
+ zval *result_p = NULL;
+
+ zend_call_method_with_2_params(&object, heap_object->std.ce, &heap_object->fptr_cmp, "compare", &result_p, a, b);
+
+ if (EG(exception)) {
+ return FAILURE;
+ }
+
+ convert_to_long(result_p);
+ *result = Z_LVAL_P(result_p);
+
+ zval_ptr_dtor(&result_p);
+
+ return SUCCESS;
+}
+/* }}} */
+
+static zval **spl_pqueue_extract_helper(zval **value, int flags) /* {{{ */
+{
+ if ((flags & SPL_PQUEUE_EXTR_BOTH) == SPL_PQUEUE_EXTR_BOTH) {
+ return value;
+ } else if ((flags & SPL_PQUEUE_EXTR_BOTH) > 0) {
+
+ if ((flags & SPL_PQUEUE_EXTR_DATA) == SPL_PQUEUE_EXTR_DATA) {
+ zval **data;
+ if (zend_hash_find(Z_ARRVAL_PP(value), "data", sizeof("data"), (void **) &data) == SUCCESS) {
+ return data;
+ }
+ } else {
+ zval **priority;
+ if (zend_hash_find(Z_ARRVAL_PP(value), "priority", sizeof("priority"), (void **) &priority) == SUCCESS) {
+ return priority;
+ }
+ }
+ }
+
+ return NULL;
+}
+/* }}} */
+
+static int spl_ptr_heap_zval_max_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */
+ zval result;
+
+ if (EG(exception)) {
+ return 0;
+ }
+
+ if (object) {
+ spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object((zval *)object TSRMLS_CC);
+ if (heap_object->fptr_cmp) {
+ long lval = 0;
+ if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, (zval *)a, (zval *)b, &lval TSRMLS_CC) == FAILURE) {
+ /* exception or call failure */
+ return 0;
+ }
+ return lval;
+ }
+ }
+
+ INIT_ZVAL(result);
+ compare_function(&result, (zval *)a, (zval *)b TSRMLS_CC);
+ return Z_LVAL(result);
+}
+/* }}} */
+
+static int spl_ptr_heap_zval_min_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */
+ zval result;
+
+ if (EG(exception)) {
+ return 0;
+ }
+
+ if (object) {
+ spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object((zval *)object TSRMLS_CC);
+ if (heap_object->fptr_cmp) {
+ long lval = 0;
+ if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, (zval *)a, (zval *)b, &lval TSRMLS_CC) == FAILURE) {
+ /* exception or call failure */
+ return 0;
+ }
+ return lval;
+ }
+ }
+
+ INIT_ZVAL(result);
+ compare_function(&result, (zval *)b, (zval *)a TSRMLS_CC);
+ return Z_LVAL(result);
+}
+/* }}} */
+
+static int spl_ptr_pqueue_zval_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */
+ zval result;
+ zval **a_priority_pp = spl_pqueue_extract_helper((zval **)&a, SPL_PQUEUE_EXTR_PRIORITY);
+ zval **b_priority_pp = spl_pqueue_extract_helper((zval **)&b, SPL_PQUEUE_EXTR_PRIORITY);
+
+ if ((!a_priority_pp) || (!b_priority_pp)) {
+ zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node");
+ return 0;
+ }
+ if (EG(exception)) {
+ return 0;
+ }
+
+ if (object) {
+ spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (heap_object->fptr_cmp) {
+ long lval = 0;
+ if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, *a_priority_pp, *b_priority_pp, &lval TSRMLS_CC) == FAILURE) {
+ /* exception or call failure */
+ return 0;
+ }
+ return lval;
+ }
+ }
+
+ INIT_ZVAL(result);
+ compare_function(&result, *a_priority_pp, *b_priority_pp TSRMLS_CC);
+ return Z_LVAL(result);
+}
+/* }}} */
+
+static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor) /* {{{ */
+{
+ spl_ptr_heap *heap = emalloc(sizeof(spl_ptr_heap));
+
+ heap->dtor = dtor;
+ heap->ctor = ctor;
+ heap->cmp = cmp;
+ heap->elements = safe_emalloc(sizeof(spl_ptr_heap_element), PTR_HEAP_BLOCK_SIZE, 0);
+ heap->max_size = PTR_HEAP_BLOCK_SIZE;
+ heap->count = 0;
+ heap->flags = 0;
+
+ return heap;
+}
+/* }}} */
+
+static void spl_ptr_heap_insert(spl_ptr_heap *heap, spl_ptr_heap_element elem, void *cmp_userdata TSRMLS_DC) { /* {{{ */
+ int i;
+
+ if (heap->count+1 > heap->max_size) {
+ /* we need to allocate more memory */
+ heap->elements = (void **) safe_erealloc(heap->elements, sizeof(spl_ptr_heap_element), (heap->max_size), (sizeof(spl_ptr_heap_element) * (heap->max_size)));
+ heap->max_size *= 2;
+ }
+
+ heap->ctor(elem TSRMLS_CC);
+
+ /* sifting up */
+ for(i = heap->count++; i > 0 && heap->cmp(heap->elements[(i-1)/2], elem, cmp_userdata TSRMLS_CC) < 0; i = (i-1)/2) {
+ heap->elements[i] = heap->elements[(i-1)/2];
+ }
+
+ if (EG(exception)) {
+ /* exception thrown during comparison */
+ heap->flags |= SPL_HEAP_CORRUPTED;
+ }
+
+ heap->elements[i] = elem;
+
+}
+/* }}} */
+
+static spl_ptr_heap_element spl_ptr_heap_top(spl_ptr_heap *heap) { /* {{{ */
+ if (heap->count == 0) {
+ return NULL;
+ }
+
+ return heap->elements[0];
+}
+/* }}} */
+
+static spl_ptr_heap_element spl_ptr_heap_delete_top(spl_ptr_heap *heap, void *cmp_userdata TSRMLS_DC) { /* {{{ */
+ int i, j;
+ const int limit = (heap->count-1)/2;
+ spl_ptr_heap_element top;
+ spl_ptr_heap_element bottom;
+
+ if (heap->count == 0) {
+ return NULL;
+ }
+
+ top = heap->elements[0];
+ bottom = heap->elements[--heap->count];
+
+ for( i = 0; i < limit; i = j)
+ {
+ /* Find smaller child */
+ j = i*2+1;
+ if(j != heap->count && heap->cmp(heap->elements[j+1], heap->elements[j], cmp_userdata TSRMLS_CC) > 0) {
+ j++; /* next child is bigger */
+ }
+
+ /* swap elements between two levels */
+ if(heap->cmp(bottom, heap->elements[j], cmp_userdata TSRMLS_CC) < 0) {
+ heap->elements[i] = heap->elements[j];
+ } else {
+ break;
+ }
+ }
+
+ if (EG(exception)) {
+ /* exception thrown during comparison */
+ heap->flags |= SPL_HEAP_CORRUPTED;
+ }
+
+ heap->elements[i] = bottom;
+ heap->dtor(top TSRMLS_CC);
+ return top;
+}
+/* }}} */
+
+static spl_ptr_heap *spl_ptr_heap_clone(spl_ptr_heap *from TSRMLS_DC) { /* {{{ */
+ int i;
+
+ spl_ptr_heap *heap = emalloc(sizeof(spl_ptr_heap));
+
+ heap->dtor = from->dtor;
+ heap->ctor = from->ctor;
+ heap->cmp = from->cmp;
+ heap->max_size = from->max_size;
+ heap->count = from->count;
+ heap->flags = from->flags;
+
+ heap->elements = safe_emalloc(sizeof(spl_ptr_heap_element),from->max_size,0);
+ memcpy(heap->elements, from->elements, sizeof(spl_ptr_heap_element)*from->max_size);
+
+ for (i=0; i < heap->count; ++i) {
+ heap->ctor(heap->elements[i] TSRMLS_CC);
+ }
+
+ return heap;
+}
+/* }}} */
+
+static void spl_ptr_heap_destroy(spl_ptr_heap *heap TSRMLS_DC) { /* {{{ */
+ int i;
+
+ for (i=0; i < heap->count; ++i) {
+ heap->dtor(heap->elements[i] TSRMLS_CC);
+ }
+
+ efree(heap->elements);
+ efree(heap);
+}
+/* }}} */
+
+static int spl_ptr_heap_count(spl_ptr_heap *heap) { /* {{{ */
+ return heap->count;
+}
+/* }}} */
+/* }}} */
+
+zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
+
+static void spl_heap_object_free_storage(void *object TSRMLS_DC) /* {{{ */
+{
+ int i;
+ spl_heap_object *intern = (spl_heap_object *)object;
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+
+ for (i = 0; i < intern->heap->count; ++i) {
+ if (intern->heap->elements[i]) {
+ zval_ptr_dtor((zval **)&intern->heap->elements[i]);
+ }
+ }
+
+ spl_ptr_heap_destroy(intern->heap TSRMLS_CC);
+
+ zval_ptr_dtor(&intern->retval);
+
+ if (intern->debug_info != NULL) {
+ zend_hash_destroy(intern->debug_info);
+ efree(intern->debug_info);
+ }
+
+ efree(object);
+}
+/* }}} */
+
+static zend_object_value spl_heap_object_new_ex(zend_class_entry *class_type, spl_heap_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */
+{
+ zend_object_value retval;
+ spl_heap_object *intern;
+ zend_class_entry *parent = class_type;
+ int inherited = 0;
+
+ intern = ecalloc(1, sizeof(spl_heap_object));
+ *obj = intern;
+ ALLOC_INIT_ZVAL(intern->retval);
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ intern->flags = 0;
+ intern->fptr_cmp = NULL;
+ intern->debug_info = NULL;
+
+ if (orig) {
+ spl_heap_object *other = (spl_heap_object*)zend_object_store_get_object(orig TSRMLS_CC);
+ intern->ce_get_iterator = other->ce_get_iterator;
+
+ if (clone_orig) {
+ int i;
+ intern->heap = spl_ptr_heap_clone(other->heap TSRMLS_CC);
+ for (i = 0; i < intern->heap->count; ++i) {
+ if (intern->heap->elements[i]) {
+ Z_ADDREF_P((zval *)intern->heap->elements[i]);
+ }
+ }
+ } else {
+ intern->heap = other->heap;
+ }
+
+ intern->flags = other->flags;
+ } else {
+ intern->heap = spl_ptr_heap_init(spl_ptr_heap_zval_max_cmp, spl_ptr_heap_zval_ctor, spl_ptr_heap_zval_dtor);
+ }
+
+ retval.handlers = &spl_handler_SplHeap;
+
+ while (parent) {
+ if (parent == spl_ce_SplPriorityQueue) {
+ intern->heap->cmp = spl_ptr_pqueue_zval_cmp;
+ intern->flags = SPL_PQUEUE_EXTR_DATA;
+ retval.handlers = &spl_handler_SplPriorityQueue;
+ break;
+ }
+
+ if (parent == spl_ce_SplMinHeap) {
+ intern->heap->cmp = spl_ptr_heap_zval_min_cmp;
+ break;
+ }
+
+ if (parent == spl_ce_SplMaxHeap) {
+ intern->heap->cmp = spl_ptr_heap_zval_max_cmp;
+ break;
+ }
+
+ if (parent == spl_ce_SplHeap) {
+ break;
+ }
+
+ parent = parent->parent;
+ inherited = 1;
+ }
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_heap_object_free_storage, NULL TSRMLS_CC);
+
+ if (!parent) { /* this must never happen */
+ php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplHeap");
+ }
+
+ if (inherited) {
+ zend_hash_find(&class_type->function_table, "compare", sizeof("compare"), (void **) &intern->fptr_cmp);
+ if (intern->fptr_cmp->common.scope == parent) {
+ intern->fptr_cmp = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
+ if (intern->fptr_count->common.scope == parent) {
+ intern->fptr_count = NULL;
+ }
+ }
+
+ return retval;
+}
+/* }}} */
+
+static zend_object_value spl_heap_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
+{
+ spl_heap_object *tmp;
+ return spl_heap_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
+}
+/* }}} */
+
+static zend_object_value spl_heap_object_clone(zval *zobject TSRMLS_DC) /* {{{ */
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_heap_object *intern;
+
+ old_object = zend_objects_get_address(zobject TSRMLS_CC);
+ new_obj_val = spl_heap_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
+ new_object = &intern->std;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ return new_obj_val;
+}
+/* }}} */
+
+static int spl_heap_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (intern->fptr_count) {
+ zval *rv;
+ zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
+ if (rv) {
+ zval_ptr_dtor(&intern->retval);
+ MAKE_STD_ZVAL(intern->retval);
+ ZVAL_ZVAL(intern->retval, rv, 1, 1);
+ convert_to_long(intern->retval);
+ *count = (long) Z_LVAL_P(intern->retval);
+ return SUCCESS;
+ }
+ *count = 0;
+ return FAILURE;
+ }
+
+ *count = spl_ptr_heap_count(intern->heap);
+
+ return SUCCESS;
+}
+/* }}} */
+
+static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zval *obj, int *is_temp TSRMLS_DC) { /* {{{ */
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(obj TSRMLS_CC);
+ zval *tmp, zrv, *heap_array;
+ char *pnstr;
+ int pnlen;
+ int i;
+
+ *is_temp = 0;
+
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+
+ if (intern->debug_info == NULL) {
+ ALLOC_HASHTABLE(intern->debug_info);
+ ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
+ }
+
+ if (intern->debug_info->nApplyCount == 0) {
+ INIT_PZVAL(&zrv);
+ Z_ARRVAL(zrv) = intern->debug_info;
+
+ zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ pnstr = spl_gen_private_prop_name(ce, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC);
+ add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags);
+ efree(pnstr);
+
+ pnstr = spl_gen_private_prop_name(ce, "isCorrupted", sizeof("isCorrupted")-1, &pnlen TSRMLS_CC);
+ add_assoc_bool_ex(&zrv, pnstr, pnlen+1, intern->heap->flags&SPL_HEAP_CORRUPTED);
+ efree(pnstr);
+
+ ALLOC_INIT_ZVAL(heap_array);
+ array_init(heap_array);
+
+ for (i = 0; i < intern->heap->count; ++i) {
+ add_index_zval(heap_array, i, (zval *)intern->heap->elements[i]);
+ Z_ADDREF_P(intern->heap->elements[i]);
+ }
+
+ pnstr = spl_gen_private_prop_name(ce, "heap", sizeof("heap")-1, &pnlen TSRMLS_CC);
+ add_assoc_zval_ex(&zrv, pnstr, pnlen+1, heap_array);
+ efree(pnstr);
+ }
+
+ return intern->debug_info;
+}
+/* }}} */
+
+static HashTable* spl_heap_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
+{
+ return spl_heap_object_get_debug_info_helper(spl_ce_SplHeap, obj, is_temp TSRMLS_CC);
+}
+/* }}} */
+
+static HashTable* spl_pqueue_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
+{
+ return spl_heap_object_get_debug_info_helper(spl_ce_SplPriorityQueue, obj, is_temp TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int SplHeap::count() U
+ Return the number of elements in the heap. */
+SPL_METHOD(SplHeap, count)
+{
+ long count;
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ count = spl_ptr_heap_count(intern->heap);
+ RETURN_LONG(count);
+}
+/* }}} */
+
+/* {{{ proto int SplHeap::isEmpty() U
+ Return true if the heap is empty. */
+SPL_METHOD(SplHeap, isEmpty)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(spl_ptr_heap_count(intern->heap)==0);
+}
+/* }}} */
+
+/* {{{ proto bool SplHeap::insert(mixed $value) U
+ Push $value on the heap */
+SPL_METHOD(SplHeap, insert)
+{
+ zval *value;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ SEPARATE_ARG_IF_REF(value);
+
+ spl_ptr_heap_insert(intern->heap, value, getThis() TSRMLS_CC);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto mixed SplHeap::extract() U
+ extract the element out of the top of the heap */
+SPL_METHOD(SplHeap, extract)
+{
+ zval *value;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ value = (zval *)spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC);
+
+ if (!value) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 1);
+}
+/* }}} */
+
+/* {{{ proto bool SplPriorityQueue::insert(mixed $value, mixed $priority) U
+ Push $value with the priority $priodiry on the priorityqueue */
+SPL_METHOD(SplPriorityQueue, insert)
+{
+ zval *data, *priority, *elem;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &data, &priority) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ SEPARATE_ARG_IF_REF(data);
+ SEPARATE_ARG_IF_REF(priority);
+
+ ALLOC_INIT_ZVAL(elem);
+
+ array_init(elem);
+ add_assoc_zval_ex(elem, "data", sizeof("data"), data);
+ add_assoc_zval_ex(elem, "priority", sizeof("priority"), priority);
+
+ spl_ptr_heap_insert(intern->heap, elem, getThis() TSRMLS_CC);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto mixed SplPriorityQueue::extract() U
+ extract the element out of the top of the priority queue */
+SPL_METHOD(SplPriorityQueue, extract)
+{
+ zval *value, *value_out, **value_out_pp;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ value = (zval *)spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC);
+
+ if (!value) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0 TSRMLS_CC);
+ return;
+ }
+
+ value_out_pp = spl_pqueue_extract_helper(&value, intern->flags);
+
+
+ if (!value_out_pp) {
+ zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node");
+ zval_ptr_dtor(&value);
+ return;
+ }
+
+ value_out = *value_out_pp;
+
+ Z_ADDREF_P(value_out);
+ zval_ptr_dtor(&value);
+
+ RETURN_ZVAL(value_out, 1, 1);
+}
+/* }}} */
+
+/* {{{ proto mixed SplPriorityQueue::top() U
+ Peek at the top element of the priority queue */
+SPL_METHOD(SplPriorityQueue, top)
+{
+ zval *value, **value_out;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ value = (zval *)spl_ptr_heap_top(intern->heap);
+
+ if (!value) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0 TSRMLS_CC);
+ return;
+ }
+
+ value_out = spl_pqueue_extract_helper(&value, intern->flags);
+
+ if (!value_out) {
+ zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node");
+ return;
+ }
+
+ RETURN_ZVAL(*value_out, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto int SplPriorityQueue::setIteratorMode($flags) U
+ Set the flags of extraction*/
+SPL_METHOD(SplPriorityQueue, setExtractFlags)
+{
+ long value;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ intern->flags = value & SPL_PQUEUE_EXTR_MASK;
+
+ RETURN_LONG(intern->flags);
+}
+/* }}} */
+
+/* {{{ proto int SplHeap::recoverFromCorruption() U
+ Recover from a corrupted state*/
+SPL_METHOD(SplHeap, recoverFromCorruption)
+{
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ intern->heap->flags = intern->heap->flags & ~SPL_HEAP_CORRUPTED;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool SplPriorityQueue::compare(mixed $a, mixed $b) U
+ compare the priorities */
+SPL_METHOD(SplPriorityQueue, compare)
+{
+ zval *a, *b;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(spl_ptr_heap_zval_max_cmp(a, b, NULL TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto mixed SplHeap::top() U
+ Peek at the top element of the heap */
+SPL_METHOD(SplHeap, top)
+{
+ zval *value;
+ spl_heap_object *intern;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
+ return;
+ }
+
+ intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ value = (zval *)spl_ptr_heap_top(intern->heap);
+
+ if (!value) {
+ zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0 TSRMLS_CC);
+ return;
+ }
+
+ RETURN_ZVAL(value, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto bool SplMinHeap::compare(mixed $a, mixed $b) U
+ compare the values */
+SPL_METHOD(SplMinHeap, compare)
+{
+ zval *a, *b;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(spl_ptr_heap_zval_min_cmp(a, b, NULL TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto bool SplMaxHeap::compare(mixed $a, mixed $b) U
+ compare the values */
+SPL_METHOD(SplMaxHeap, compare)
+{
+ zval *a, *b;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(spl_ptr_heap_zval_max_cmp(a, b, NULL TSRMLS_CC));
+}
+/* }}} */
+
+static void spl_heap_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ zval_ptr_dtor((zval**)&iterator->intern.it.data);
+
+ efree(iterator);
+}
+/* }}} */
+
+static void spl_heap_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ /* do nothing, the iterator always points to the top element */
+}
+/* }}} */
+
+static int spl_heap_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+
+ return (iterator->object->heap->count != 0 ? SUCCESS : FAILURE);
+}
+/* }}} */
+
+static void spl_heap_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+ zval **element = (zval **)&iterator->object->heap->elements[0];
+
+ if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ if (iterator->object->heap->count == 0 || !*element) {
+ *data = NULL;
+ } else {
+ *data = element;
+ }
+}
+/* }}} */
+
+static void spl_pqueue_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+ zval **element = (zval **)&iterator->object->heap->elements[0];
+
+ if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ if (iterator->object->heap->count == 0 || !*element) {
+ *data = NULL;
+ } else {
+ *data = spl_pqueue_extract_helper(element, iterator->object->flags);
+ if (!*data) {
+ zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node");
+ }
+ }
+}
+/* }}} */
+
+static int spl_heap_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+
+ *int_key = (ulong) iterator->object->heap->count - 1;
+ return HASH_KEY_IS_LONG;
+}
+/* }}} */
+
+static void spl_heap_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
+{
+ zval *object = (zval*)((zend_user_iterator *)iter)->it.data;
+ spl_heap_it *iterator = (spl_heap_it *)iter;
+ spl_ptr_heap_element elem;
+
+ if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) {
+ zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC);
+ return;
+ }
+
+ elem = spl_ptr_heap_delete_top(iterator->object->heap, object TSRMLS_CC);
+
+ if (elem != NULL) {
+ zval_ptr_dtor((zval **)&elem);
+ }
+
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int SplHeap::key() U
+ Return current array key */
+SPL_METHOD(SplHeap, key)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->heap->count - 1);
+}
+/* }}} */
+
+/* {{{ proto void SplHeap::next() U
+ Move to next entry */
+SPL_METHOD(SplHeap, next)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_ptr_heap_element elem = spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (elem != NULL) {
+ zval_ptr_dtor((zval **)&elem);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool SplHeap::valid() U
+ Check whether the datastructure contains more entries */
+SPL_METHOD(SplHeap, valid)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(intern->heap->count != 0);
+}
+/* }}} */
+
+/* {{{ proto void SplHeap::rewind() U
+ Rewind the datastructure back to the start */
+SPL_METHOD(SplHeap, rewind)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* do nothing, the iterator always points to the top element */
+}
+/* }}} */
+
+/* {{{ proto mixed|NULL SplHeap::current() U
+ Return current datastructure entry */
+SPL_METHOD(SplHeap, current)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *element = (zval *)intern->heap->elements[0];
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!intern->heap->count || !element) {
+ RETURN_NULL();
+ } else {
+ RETURN_ZVAL(element, 1, 0);
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed|NULL SplPriorityQueue::current() U
+ Return current datastructure entry */
+SPL_METHOD(SplPriorityQueue, current)
+{
+ spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval **element = (zval **)&intern->heap->elements[0];
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!intern->heap->count || !*element) {
+ RETURN_NULL();
+ } else {
+ zval **data = spl_pqueue_extract_helper(element, intern->flags);
+
+ if (!data) {
+ zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node");
+ RETURN_NULL();
+ }
+
+ RETURN_ZVAL(*data, 1, 0);
+ }
+}
+/* }}} */
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_heap_it_funcs = {
+ spl_heap_it_dtor,
+ spl_heap_it_valid,
+ spl_heap_it_get_current_data,
+ spl_heap_it_get_current_key,
+ spl_heap_it_move_forward,
+ spl_heap_it_rewind
+};
+
+zend_object_iterator_funcs spl_pqueue_it_funcs = {
+ spl_heap_it_dtor,
+ spl_heap_it_valid,
+ spl_pqueue_it_get_current_data,
+ spl_heap_it_get_current_key,
+ spl_heap_it_move_forward,
+ spl_heap_it_rewind
+};
+
+zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator;
+ spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (by_ref) {
+ zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ Z_ADDREF_P(object);
+
+ iterator = emalloc(sizeof(spl_heap_it));
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_heap_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
+ iterator->flags = heap_object->flags;
+ iterator->object = heap_object;
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+zend_object_iterator *spl_pqueue_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
+{
+ spl_heap_it *iterator;
+ spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ if (by_ref) {
+ zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ Z_ADDREF_P(object);
+
+ iterator = emalloc(sizeof(spl_heap_it));
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_pqueue_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
+ iterator->flags = heap_object->flags;
+ iterator->object = heap_object;
+
+ return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_heap_insert, 0)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_heap_compare, 0)
+ ZEND_ARG_INFO(0, a)
+ ZEND_ARG_INFO(0, b)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_pqueue_insert, 0)
+ ZEND_ARG_INFO(0, value)
+ ZEND_ARG_INFO(0, priority)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_pqueue_setflags, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_splheap_void, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_funcs_SplMinHeap[] = {
+ SPL_ME(SplMinHeap, compare, arginfo_heap_compare, ZEND_ACC_PROTECTED)
+ {NULL, NULL, NULL}
+};
+static const zend_function_entry spl_funcs_SplMaxHeap[] = {
+ SPL_ME(SplMaxHeap, compare, arginfo_heap_compare, ZEND_ACC_PROTECTED)
+ {NULL, NULL, NULL}
+};
+
+static const zend_function_entry spl_funcs_SplPriorityQueue[] = {
+ SPL_ME(SplPriorityQueue, compare, arginfo_heap_compare, ZEND_ACC_PUBLIC)
+ SPL_ME(SplPriorityQueue, insert, arginfo_pqueue_insert, ZEND_ACC_PUBLIC)
+ SPL_ME(SplPriorityQueue, setExtractFlags, arginfo_pqueue_setflags, ZEND_ACC_PUBLIC)
+ SPL_ME(SplPriorityQueue, top, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplPriorityQueue, extract, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, count, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, isEmpty, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, rewind, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplPriorityQueue, current, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, key, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, next, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+
+static const zend_function_entry spl_funcs_SplHeap[] = {
+ SPL_ME(SplHeap, extract, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, insert, arginfo_heap_insert, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, top, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, count, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, isEmpty, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, rewind, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, current, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, key, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, next, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC)
+ ZEND_FENTRY(compare, NULL, NULL, ZEND_ACC_PROTECTED|ZEND_ACC_ABSTRACT)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+PHP_MINIT_FUNCTION(spl_heap) /* {{{ */
+{
+ REGISTER_SPL_STD_CLASS_EX(SplHeap, spl_heap_object_new, spl_funcs_SplHeap);
+ memcpy(&spl_handler_SplHeap, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_SplHeap.clone_obj = spl_heap_object_clone;
+ spl_handler_SplHeap.count_elements = spl_heap_object_count_elements;
+ spl_handler_SplHeap.get_debug_info = spl_heap_object_get_debug_info;
+
+ REGISTER_SPL_IMPLEMENTS(SplHeap, Iterator);
+ REGISTER_SPL_IMPLEMENTS(SplHeap, Countable);
+
+ spl_ce_SplHeap->get_iterator = spl_heap_get_iterator;
+
+ REGISTER_SPL_SUB_CLASS_EX(SplMinHeap, SplHeap, spl_heap_object_new, spl_funcs_SplMinHeap);
+ REGISTER_SPL_SUB_CLASS_EX(SplMaxHeap, SplHeap, spl_heap_object_new, spl_funcs_SplMaxHeap);
+
+ spl_ce_SplMaxHeap->get_iterator = spl_heap_get_iterator;
+ spl_ce_SplMinHeap->get_iterator = spl_heap_get_iterator;
+
+ REGISTER_SPL_STD_CLASS_EX(SplPriorityQueue, spl_heap_object_new, spl_funcs_SplPriorityQueue);
+ memcpy(&spl_handler_SplPriorityQueue, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_SplPriorityQueue.clone_obj = spl_heap_object_clone;
+ spl_handler_SplPriorityQueue.count_elements = spl_heap_object_count_elements;
+ spl_handler_SplPriorityQueue.get_debug_info = spl_pqueue_object_get_debug_info;
+
+ REGISTER_SPL_IMPLEMENTS(SplPriorityQueue, Iterator);
+ REGISTER_SPL_IMPLEMENTS(SplPriorityQueue, Countable);
+
+ spl_ce_SplPriorityQueue->get_iterator = spl_pqueue_get_iterator;
+
+ REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_BOTH", SPL_PQUEUE_EXTR_BOTH);
+ REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_PRIORITY", SPL_PQUEUE_EXTR_PRIORITY);
+ REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_DATA", SPL_PQUEUE_EXTR_DATA);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
+
diff --git a/ext/spl/spl_heap.h b/ext/spl/spl_heap.h
new file mode 100644
index 0000000..11bce04
--- /dev/null
+++ b/ext/spl/spl_heap.h
@@ -0,0 +1,44 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_HEAP_H
+#define SPL_HEAP_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_SplHeap;
+extern PHPAPI zend_class_entry *spl_ce_SplMinHeap;
+extern PHPAPI zend_class_entry *spl_ce_SplMaxHeap;
+
+extern PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
+
+PHP_MINIT_FUNCTION(spl_heap);
+
+#endif /* SPL_HEAP_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
new file mode 100644
index 0000000..e6cd155
--- /dev/null
+++ b/ext/spl/spl_iterators.c
@@ -0,0 +1,3774 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_exceptions.h"
+#include "zend_interfaces.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+#include "spl_directory.h"
+#include "spl_array.h"
+#include "spl_exceptions.h"
+#include "ext/standard/php_smart_str.h"
+
+#ifdef accept
+#undef accept
+#endif
+
+PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
+PHPAPI zend_class_entry *spl_ce_FilterIterator;
+PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator;
+PHPAPI zend_class_entry *spl_ce_ParentIterator;
+PHPAPI zend_class_entry *spl_ce_SeekableIterator;
+PHPAPI zend_class_entry *spl_ce_LimitIterator;
+PHPAPI zend_class_entry *spl_ce_CachingIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
+PHPAPI zend_class_entry *spl_ce_OuterIterator;
+PHPAPI zend_class_entry *spl_ce_IteratorIterator;
+PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
+PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
+PHPAPI zend_class_entry *spl_ce_EmptyIterator;
+PHPAPI zend_class_entry *spl_ce_AppendIterator;
+PHPAPI zend_class_entry *spl_ce_RegexIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
+PHPAPI zend_class_entry *spl_ce_Countable;
+PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
+
+ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
+ZEND_END_ARG_INFO()
+
+const zend_function_entry spl_funcs_RecursiveIterator[] = {
+ SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, arginfo_recursive_it_void)
+ SPL_ABSTRACT_ME(RecursiveIterator, getChildren, arginfo_recursive_it_void)
+ PHP_FE_END
+};
+
+typedef enum {
+ RIT_LEAVES_ONLY = 0,
+ RIT_SELF_FIRST = 1,
+ RIT_CHILD_FIRST = 2
+} RecursiveIteratorMode;
+
+#define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
+
+typedef enum {
+ RTIT_BYPASS_CURRENT = 4,
+ RTIT_BYPASS_KEY = 8
+} RecursiveTreeIteratorFlags;
+
+typedef enum {
+ RS_NEXT = 0,
+ RS_TEST = 1,
+ RS_SELF = 2,
+ RS_CHILD = 3,
+ RS_START = 4
+} RecursiveIteratorState;
+
+typedef struct _spl_sub_iterator {
+ zend_object_iterator *iterator;
+ zval *zobject;
+ zend_class_entry *ce;
+ RecursiveIteratorState state;
+} spl_sub_iterator;
+
+typedef struct _spl_recursive_it_object {
+ zend_object std;
+ spl_sub_iterator *iterators;
+ int level;
+ RecursiveIteratorMode mode;
+ int flags;
+ int max_depth;
+ zend_bool in_iteration;
+ zend_function *beginIteration;
+ zend_function *endIteration;
+ zend_function *callHasChildren;
+ zend_function *callGetChildren;
+ zend_function *beginChildren;
+ zend_function *endChildren;
+ zend_function *nextElement;
+ zend_class_entry *ce;
+ smart_str prefix[6];
+} spl_recursive_it_object;
+
+typedef struct _spl_recursive_it_iterator {
+ zend_object_iterator intern;
+ zval *zobject;
+} spl_recursive_it_iterator;
+
+static zend_object_handlers spl_handlers_rec_it_it;
+static zend_object_handlers spl_handlers_dual_it;
+
+#define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
+ do { \
+ spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \
+ if (it->dit_type == DIT_Unknown) { \
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \
+ "The object is in an invalid state as the parent constructor was not called"); \
+ return; \
+ } \
+ (var) = it; \
+ } while (0)
+
+static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
+{
+ spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter;
+ spl_recursive_it_object *object = (spl_recursive_it_object*)_iter->data;
+ zend_object_iterator *sub_iter;
+
+ while (object->level > 0) {
+ sub_iter = object->iterators[object->level].iterator;
+ sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+ zval_ptr_dtor(&object->iterators[object->level--].zobject);
+ }
+ object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
+ object->level = 0;
+
+ zval_ptr_dtor(&iter->zobject);
+ efree(iter);
+}
+
+static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
+{
+ zend_object_iterator *sub_iter;
+ int level = object->level;
+
+ while (level >=0) {
+ sub_iter = object->iterators[level].iterator;
+ if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ }
+ level--;
+ }
+ if (object->endIteration && object->in_iteration) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL);
+ }
+ object->in_iteration = 0;
+ return FAILURE;
+}
+
+static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
+
+ return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
+}
+
+static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
+ zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
+
+ sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
+}
+
+static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
+ zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
+
+ if (sub_iter->funcs->get_current_key) {
+ return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
+ } else {
+ *int_key = iter->index;
+ return HASH_KEY_IS_LONG;
+ }
+}
+
+static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
+{
+ zend_object_iterator *iterator;
+ zval *zobject;
+ zend_class_entry *ce;
+ zval *retval, *child;
+ zend_object_iterator *sub_iter;
+ int has_children;
+
+ while (!EG(exception)) {
+next_step:
+ iterator = object->iterators[object->level].iterator;
+ switch (object->iterators[object->level].state) {
+ case RS_NEXT:
+ iterator->funcs->move_forward(iterator TSRMLS_CC);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
+ /* fall through */
+ case RS_START:
+ if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
+ break;
+ }
+ object->iterators[object->level].state = RS_TEST;
+ /* break; */
+ case RS_TEST:
+ ce = object->iterators[object->level].ce;
+ zobject = object->iterators[object->level].zobject;
+ if (object->callHasChildren) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
+ } else {
+ zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
+ }
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ object->iterators[object->level].state = RS_NEXT;
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
+ if (retval) {
+ has_children = zend_is_true(retval);
+ zval_ptr_dtor(&retval);
+ if (has_children) {
+ if (object->max_depth == -1 || object->max_depth > object->level) {
+ switch (object->mode) {
+ case RIT_LEAVES_ONLY:
+ case RIT_CHILD_FIRST:
+ object->iterators[object->level].state = RS_CHILD;
+ goto next_step;
+ case RIT_SELF_FIRST:
+ object->iterators[object->level].state = RS_SELF;
+ goto next_step;
+ }
+ } else {
+ /* do not recurse into */
+ if (object->mode == RIT_LEAVES_ONLY) {
+ /* this is not a leave, so skip it */
+ object->iterators[object->level].state = RS_NEXT;
+ goto next_step;
+ }
+ }
+ }
+ }
+ if (object->nextElement) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
+ }
+ object->iterators[object->level].state = RS_NEXT;
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
+ return /* self */;
+ case RS_SELF:
+ if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
+ }
+ if (object->mode == RIT_SELF_FIRST) {
+ object->iterators[object->level].state = RS_CHILD;
+ } else {
+ object->iterators[object->level].state = RS_NEXT;
+ }
+ return /* self */;
+ case RS_CHILD:
+ ce = object->iterators[object->level].ce;
+ zobject = object->iterators[object->level].zobject;
+ if (object->callGetChildren) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
+ } 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) {
+ zval_ptr_dtor(&child);
+ }
+ zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
+ return;
+ }
+ if (object->mode == RIT_CHILD_FIRST) {
+ object->iterators[object->level].state = RS_SELF;
+ } else {
+ object->iterators[object->level].state = RS_NEXT;
+ }
+ object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
+ sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
+ object->iterators[object->level].iterator = sub_iter;
+ object->iterators[object->level].zobject = child;
+ object->iterators[object->level].ce = ce;
+ object->iterators[object->level].state = RS_START;
+ if (sub_iter->funcs->rewind) {
+ sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
+ }
+ if (object->beginChildren) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
+ }
+ goto next_step;
+ }
+ /* no more elements */
+ if (object->level > 0) {
+ if (object->endChildren) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
+ }
+ iterator->funcs->dtor(iterator TSRMLS_CC);
+ zval_ptr_dtor(&object->iterators[object->level].zobject);
+ object->level--;
+ } else {
+ return; /* done completeley */
+ }
+ }
+}
+
+static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
+{
+ zend_object_iterator *sub_iter;
+
+ if (!object->iterators) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name);
+ }
+
+ while (object->level) {
+ sub_iter = object->iterators[object->level].iterator;
+ sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+ zval_ptr_dtor(&object->iterators[object->level--].zobject);
+ if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
+ }
+ }
+ object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
+ object->iterators[0].state = RS_START;
+ sub_iter = object->iterators[0].iterator;
+ if (sub_iter->funcs->rewind) {
+ sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
+ }
+ if (!EG(exception) && object->beginIteration && !object->in_iteration) {
+ zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
+ }
+ object->in_iteration = 1;
+ spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC);
+}
+
+static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
+}
+
+static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
+}
+
+static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
+{
+ spl_recursive_it_iterator *iterator;
+ spl_recursive_it_object *object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ iterator = emalloc(sizeof(spl_recursive_it_iterator));
+ object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
+ if (object->iterators == NULL) {
+ zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
+ "the parent constructor has not been called");
+ }
+
+ Z_ADDREF_P(zobject);
+ iterator->intern.data = (void*)object;
+ iterator->intern.funcs = ce->iterator_funcs.funcs;
+ iterator->zobject = zobject;
+ return (zend_object_iterator*)iterator;
+}
+
+zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
+ spl_recursive_it_dtor,
+ spl_recursive_it_valid,
+ spl_recursive_it_get_current_data,
+ spl_recursive_it_get_current_key,
+ spl_recursive_it_move_forward,
+ spl_recursive_it_rewind
+};
+
+static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
+{
+ zval *object = getThis();
+ spl_recursive_it_object *intern;
+ zval *iterator;
+ zend_class_entry *ce_iterator;
+ long mode, flags;
+ int inc_refcount = 1;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
+
+ switch(rit_type) {
+ case RIT_RecursiveTreeIterator: {
+
+ zval *caching_it, *caching_it_flags, *user_caching_it_flags = NULL;
+ mode = RIT_SELF_FIRST;
+ flags = RTIT_BYPASS_KEY;
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
+ if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
+ zval *aggregate = iterator;
+ zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
+ inc_refcount = 0;
+ }
+
+ MAKE_STD_ZVAL(caching_it_flags);
+ if (user_caching_it_flags) {
+ ZVAL_ZVAL(caching_it_flags, user_caching_it_flags, 1, 0);
+ } else {
+ ZVAL_LONG(caching_it_flags, CIT_CATCH_GET_CHILD);
+ }
+ spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, iterator, caching_it_flags TSRMLS_CC);
+ zval_ptr_dtor(&caching_it_flags);
+ if (inc_refcount == 0 && iterator) {
+ zval_ptr_dtor(&iterator);
+ }
+ iterator = caching_it;
+ inc_refcount = 0;
+ } else {
+ iterator = NULL;
+ }
+ break;
+ }
+ case RIT_RecursiveIteratorIterator:
+ default: {
+ mode = RIT_LEAVES_ONLY;
+ flags = 0;
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
+ if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
+ zval *aggregate = iterator;
+ zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
+ inc_refcount = 0;
+ }
+ } else {
+ iterator = NULL;
+ }
+ break;
+ }
+ }
+ if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) {
+ if (iterator && !inc_refcount) {
+ zval_ptr_dtor(&iterator);
+ }
+ zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ 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->flags = flags;
+ intern->max_depth = -1;
+ intern->in_iteration = 0;
+ intern->ce = Z_OBJCE_P(object);
+
+ zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration);
+ if (intern->beginIteration->common.scope == ce_base) {
+ intern->beginIteration = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration);
+ if (intern->endIteration->common.scope == ce_base) {
+ intern->endIteration = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
+ if (intern->callHasChildren->common.scope == ce_base) {
+ intern->callHasChildren = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
+ if (intern->callGetChildren->common.scope == ce_base) {
+ intern->callGetChildren = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
+ if (intern->beginChildren->common.scope == ce_base) {
+ intern->beginChildren = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
+ if (intern->endChildren->common.scope == ce_base) {
+ intern->endChildren = NULL;
+ }
+ zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement);
+ if (intern->nextElement->common.scope == ce_base) {
+ intern->nextElement = NULL;
+ }
+ ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
+ intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
+ if (inc_refcount) {
+ Z_ADDREF_P(iterator);
+ }
+ intern->iterators[0].zobject = iterator;
+ intern->iterators[0].ce = ce_iterator;
+ intern->iterators[0].state = RS_START;
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+
+ if (EG(exception)) {
+ zend_object_iterator *sub_iter;
+
+ while (intern->level >= 0) {
+ sub_iter = intern->iterators[intern->level].iterator;
+ sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+ zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
+ }
+ efree(intern->iterators);
+ intern->iterators = NULL;
+ }
+}
+
+/* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException
+ Creates a RecursiveIteratorIterator from a RecursiveIterator. */
+SPL_METHOD(RecursiveIteratorIterator, __construct)
+{
+ spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::rewind()
+ Rewind the iterator to the first element of the top level inner iterator. */
+SPL_METHOD(RecursiveIteratorIterator, rewind)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool RecursiveIteratorIterator::valid()
+ Check whether the current position is valid */
+SPL_METHOD(RecursiveIteratorIterator, valid)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS);
+} /* }}} */
+
+/* {{{ proto mixed RecursiveIteratorIterator::key()
+ Access the current key */
+SPL_METHOD(RecursiveIteratorIterator, key)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_object_iterator *iterator = object->iterators[object->level].iterator;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (iterator->funcs->get_current_key) {
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+
+ switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
+ case HASH_KEY_IS_LONG:
+ RETURN_LONG(int_key);
+ break;
+ case HASH_KEY_IS_STRING:
+ RETURN_STRINGL(str_key, str_key_len-1, 0);
+ break;
+ default:
+ RETURN_NULL();
+ }
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+/* {{{ proto mixed RecursiveIteratorIterator::current()
+ Access the current element value */
+SPL_METHOD(RecursiveIteratorIterator, current)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_object_iterator *iterator = object->iterators[object->level].iterator;
+ zval **data;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+ if (data && *data) {
+ RETURN_ZVAL(*data, 1, 0);
+ }
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::next()
+ Move forward to the next element */
+SPL_METHOD(RecursiveIteratorIterator, next)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto int RecursiveIteratorIterator::getDepth()
+ Get the current depth of the recursive iteration */
+SPL_METHOD(RecursiveIteratorIterator, getDepth)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(object->level);
+} /* }}} */
+
+/* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
+ The current active sub iterator or the iterator at specified level */
+SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long level = object->level;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
+ return;
+ }
+ if (level < 0 || level > object->level) {
+ RETURN_NULL();
+ }
+ RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
+} /* }}} */
+
+/* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator()
+ The current active sub iterator */
+SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long level = object->level;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
+} /* }}} */
+
+/* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration()
+ Called when iteration begins (after first rewind() call) */
+SPL_METHOD(RecursiveIteratorIterator, beginIteration)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration()
+ Called when iteration ends (when valid() first returns false */
+SPL_METHOD(RecursiveIteratorIterator, endIteration)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto bool RecursiveIteratorIterator::callHasChildren()
+ Called for each element to test whether it has children */
+SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = object->iterators[object->level].ce;
+ zval *retval, *zobject;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zobject = object->iterators[object->level].zobject;
+ if (!zobject) {
+ RETURN_FALSE;
+ } else {
+ zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ } else {
+ RETURN_FALSE;
+ }
+ }
+} /* }}} */
+
+/* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren()
+ Return children of current element */
+SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_class_entry *ce = object->iterators[object->level].ce;
+ zval *retval, *zobject;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zobject = object->iterators[object->level].zobject;
+ if (!zobject) {
+ return;
+ } else {
+ zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ }
+ }
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::beginChildren()
+ Called when recursing one level down */
+SPL_METHOD(RecursiveIteratorIterator, beginChildren)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::endChildren()
+ Called when end recursing one level */
+SPL_METHOD(RecursiveIteratorIterator, endChildren)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::nextElement()
+ Called when the next element is available */
+SPL_METHOD(RecursiveIteratorIterator, nextElement)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1])
+ Set the maximum allowed depth (or any depth if pmax_depth = -1] */
+SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long max_depth = -1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) {
+ return;
+ }
+ if (max_depth < -1) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC);
+ return;
+ }
+ object->max_depth = max_depth;
+} /* }}} */
+
+/* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth()
+ Return the maximum accepted depth or false if any depth is allowed */
+SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (object->max_depth == -1) {
+ RETURN_FALSE;
+ } else {
+ RETURN_LONG(object->max_depth);
+ }
+} /* }}} */
+
+static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC)
+{
+ union _zend_function *function_handler;
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
+ long level = object->level;
+ zval *zobj;
+
+ if (!object->iterators) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_PP(object_ptr)->name);
+ }
+ zobj = object->iterators[level].zobject;
+
+ function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC);
+ if (!function_handler) {
+ if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
+ if (Z_OBJ_HT_P(zobj)->get_method) {
+ *object_ptr = zobj;
+ function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC);
+ }
+ }
+ }
+ return function_handler;
+}
+
+/* {{{ spl_RecursiveIteratorIterator_dtor */
+static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object *)_object;
+ zend_object_iterator *sub_iter;
+
+ /* call standard dtor */
+ zend_objects_destroy_object(_object, handle TSRMLS_CC);
+
+ if (object->iterators) {
+ while (object->level >= 0) {
+ sub_iter = object->iterators[object->level].iterator;
+ sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+ zval_ptr_dtor(&object->iterators[object->level--].zobject);
+ }
+ efree(object->iterators);
+ object->iterators = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ spl_RecursiveIteratorIterator_free_storage */
+static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object *)_object;
+
+ zend_object_std_dtor(&object->std TSRMLS_CC);
+ smart_str_free(&object->prefix[0]);
+ smart_str_free(&object->prefix[1]);
+ smart_str_free(&object->prefix[2]);
+ smart_str_free(&object->prefix[3]);
+ smart_str_free(&object->prefix[4]);
+ smart_str_free(&object->prefix[5]);
+
+ efree(object);
+}
+/* }}} */
+
+/* {{{ spl_RecursiveIteratorIterator_new_ex */
+static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix TSRMLS_DC)
+{
+ zend_object_value retval;
+ spl_recursive_it_object *intern;
+
+ intern = emalloc(sizeof(spl_recursive_it_object));
+ memset(intern, 0, sizeof(spl_recursive_it_object));
+
+ if (init_prefix) {
+ smart_str_appendl(&intern->prefix[0], "", 0);
+ smart_str_appendl(&intern->prefix[1], "| ", 2);
+ smart_str_appendl(&intern->prefix[2], " ", 2);
+ smart_str_appendl(&intern->prefix[3], "|-", 2);
+ smart_str_appendl(&intern->prefix[4], "\\-", 2);
+ smart_str_appendl(&intern->prefix[5], "", 0);
+ }
+
+ 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)spl_RecursiveIteratorIterator_dtor, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &spl_handlers_rec_it_it;
+ return retval;
+}
+/* }}} */
+
+/* {{{ spl_RecursiveIteratorIterator_new */
+static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_RecursiveTreeIterator_new */
+static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC);
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
+ ZEND_ARG_INFO(0, level)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
+ ZEND_ARG_INFO(0, max_depth)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
+ SPL_ME(RecursiveIteratorIterator, __construct, arginfo_recursive_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, getDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, setMaxDepth, arginfo_recursive_it_setMaxDepth, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, getMaxDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value TSRMLS_DC)
+{
+ smart_str str = {0};
+ zval *has_next;
+ int level;
+
+ smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len);
+
+ for (level = 0; level < object->level; ++level) {
+ zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
+ if (has_next) {
+ if (Z_LVAL_P(has_next)) {
+ smart_str_appendl(&str, object->prefix[1].c, object->prefix[1].len);
+ } else {
+ smart_str_appendl(&str, object->prefix[2].c, object->prefix[2].len);
+ }
+ zval_ptr_dtor(&has_next);
+ }
+ }
+ zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
+ if (has_next) {
+ if (Z_LVAL_P(has_next)) {
+ smart_str_appendl(&str, object->prefix[3].c, object->prefix[3].len);
+ } else {
+ smart_str_appendl(&str, object->prefix[4].c, object->prefix[4].len);
+ }
+ zval_ptr_dtor(&has_next);
+ }
+
+ smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len);
+ smart_str_0(&str);
+
+ RETVAL_STRINGL(str.c, str.len, 0);
+}
+
+static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
+{
+ zend_object_iterator *iterator = object->iterators[object->level].iterator;
+ zval **data;
+ zend_error_handling error_handling;
+
+ iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+
+ zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
+ if (data && *data) {
+ RETVAL_ZVAL(*data, 1, 0);
+ }
+ if (Z_TYPE_P(return_value) == IS_ARRAY) {
+ zval_dtor(return_value);
+ ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1);
+ } else {
+ convert_to_string(return_value);
+ }
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+
+static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
+{
+ RETVAL_STRINGL("", 0, 1);
+}
+
+/* {{{ proto void RecursiveTreeIterator::__construct(RecursiveIterator|IteratorAggregate it [, int flags = RTIT_BYPASS_KEY [, int cit_flags = CIT_CATCH_GET_CHILD [, mode = RIT_SELF_FIRST ]]]) throws InvalidArgumentException
+ RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */
+SPL_METHOD(RecursiveTreeIterator, __construct)
+{
+ spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
+} /* }}} */
+
+/* {{{ proto void RecursiveTreeIterator::setPrefixPart(int part, string prefix) throws OutOfRangeException
+ Sets prefix parts as used in getPrefix() */
+SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long part;
+ char* prefix;
+ int prefix_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, &prefix, &prefix_len) == FAILURE) {
+ return;
+ }
+ if (0 > part || part > 5) {
+ zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant");
+ return;
+ }
+
+ smart_str_free(&object->prefix[part]);
+ smart_str_appendl(&object->prefix[part], prefix, prefix_len);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getPrefix()
+ Returns the string to place in front of current element */
+SPL_METHOD(RecursiveTreeIterator, getPrefix)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getEntry()
+ Returns the string presentation built for current element */
+SPL_METHOD(RecursiveTreeIterator, getEntry)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getPostfix()
+ Returns the string to place after the current element */
+SPL_METHOD(RecursiveTreeIterator, getPostfix)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto mixed RecursiveTreeIterator::current()
+ Returns the current element prefixed and postfixed */
+SPL_METHOD(RecursiveTreeIterator, current)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval prefix, entry, postfix;
+ char *str, *ptr;
+ size_t str_len;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (object->flags & RTIT_BYPASS_CURRENT) {
+ zend_object_iterator *iterator = object->iterators[object->level].iterator;
+ zval **data;
+
+ iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+ if (data && *data) {
+ RETURN_ZVAL(*data, 1, 0);
+ } else {
+ RETURN_NULL();
+ }
+ }
+
+ spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
+ spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC);
+ spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
+
+ str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix);
+ str = (char *) emalloc(str_len + 1U);
+ ptr = str;
+
+ memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
+ ptr += Z_STRLEN(prefix);
+ memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
+ ptr += Z_STRLEN(entry);
+ memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
+ ptr += Z_STRLEN(postfix);
+ *ptr = 0;
+
+ zval_dtor(&prefix);
+ zval_dtor(&entry);
+ zval_dtor(&postfix);
+
+ RETURN_STRINGL(str, str_len, 0);
+} /* }}} */
+
+/* {{{ proto mixed RecursiveTreeIterator::key()
+ Returns the current key prefixed and postfixed */
+SPL_METHOD(RecursiveTreeIterator, key)
+{
+ spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_object_iterator *iterator = object->iterators[object->level].iterator;
+ zval prefix, key, postfix, key_copy;
+ char *str, *ptr;
+ size_t str_len;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (iterator->funcs->get_current_key) {
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+
+ switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
+ case HASH_KEY_IS_LONG:
+ ZVAL_LONG(&key, int_key);
+ break;
+ case HASH_KEY_IS_STRING:
+ ZVAL_STRINGL(&key, str_key, str_key_len-1, 0);
+ break;
+ default:
+ ZVAL_NULL(&key);
+ }
+ } else {
+ ZVAL_NULL(&key);
+ }
+
+ if (object->flags & RTIT_BYPASS_KEY) {
+ zval *key_ptr = &key;
+ RETVAL_ZVAL(key_ptr, 1, 0);
+ zval_dtor(&key);
+ return;
+ }
+
+ if (Z_TYPE(key) != IS_STRING) {
+ int use_copy;
+ zend_make_printable_zval(&key, &key_copy, &use_copy);
+ if (use_copy) {
+ key = key_copy;
+ }
+ }
+
+ spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
+ spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
+
+ str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix);
+ str = (char *) emalloc(str_len + 1U);
+ ptr = str;
+
+ memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
+ ptr += Z_STRLEN(prefix);
+ memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
+ ptr += Z_STRLEN(key);
+ memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
+ ptr += Z_STRLEN(postfix);
+ *ptr = 0;
+
+ zval_dtor(&prefix);
+ zval_dtor(&key);
+ zval_dtor(&postfix);
+
+ RETVAL_STRINGL(str, str_len, 0);
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, caching_it_flags)
+ ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
+ ZEND_ARG_INFO(0, part)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
+ SPL_ME(RecursiveTreeIterator, __construct, arginfo_recursive_tree_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, getPrefix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, setPrefixPart, arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, getEntry, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveTreeIterator, getPostfix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+#if MBO_0
+static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
+{
+ class_type->iterator_funcs.zf_valid = NULL;
+ class_type->iterator_funcs.zf_current = NULL;
+ class_type->iterator_funcs.zf_key = NULL;
+ class_type->iterator_funcs.zf_next = NULL;
+ class_type->iterator_funcs.zf_rewind = NULL;
+ if (!class_type->iterator_funcs.funcs) {
+ class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
+ }
+
+ return SUCCESS;
+}
+#endif
+
+static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC)
+{
+ union _zend_function *function_handler;
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
+
+ function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC);
+ if (!function_handler && intern->inner.ce) {
+ if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
+ if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) {
+ *object_ptr = intern->inner.zobject;
+ function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC);
+ }
+ } else {
+ *object_ptr = intern->inner.zobject;
+ }
+ }
+ return function_handler;
+}
+
+#if MBO_0
+int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval ***func_params, func;
+ zval *retval_ptr;
+ int arg_count;
+ int current = 0;
+ int success;
+ void **p;
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ ZVAL_STRING(&func, method, 0);
+ if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
+ return FAILURE;
+ }
+
+ p = EG(argument_stack).top_element-2;
+ arg_count = (ulong) *p;
+
+ func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
+
+ current = 0;
+ while (arg_count-- > 0) {
+ func_params[current] = (zval **) p - (arg_count-current);
+ current++;
+ }
+ arg_count = current; /* restore */
+
+ if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
+ RETURN_ZVAL(retval_ptr, 0, 1);
+
+ success = SUCCESS;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
+ success = FAILURE;
+ }
+
+ efree(func_params);
+ return success;
+}
+#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)
+{
+ int cnt = 0;
+
+ cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
+
+ return cnt <= 1 ? SUCCESS : FAILURE;
+}
+
+static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
+{
+ zval *zobject, *retval;
+ spl_dual_it_object *intern;
+ zend_class_entry *ce = NULL;
+ int inc_refcount = 1;
+ zend_error_handling error_handling;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->dit_type != DIT_Unknown) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name);
+ return NULL;
+ }
+
+ zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
+
+ intern->dit_type = dit_type;
+ switch (dit_type) {
+ case DIT_LimitIterator: {
+ intern->u.limit.offset = 0; /* start at beginning */
+ intern->u.limit.count = -1; /* get all */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ if (intern->u.limit.offset < 0) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
+ zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ break;
+ }
+ case DIT_CachingIterator:
+ case DIT_RecursiveCachingIterator: {
+ long flags = CIT_CALL_TOSTRING;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ if (spl_cit_check_flags(flags) != SUCCESS) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT", 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ intern->u.caching.flags |= flags & CIT_PUBLIC;
+ MAKE_STD_ZVAL(intern->u.caching.zcache);
+ array_init(intern->u.caching.zcache);
+ break;
+ }
+ case DIT_IteratorIterator: {
+ zend_class_entry **pce_cast;
+ char * class_name = NULL;
+ int class_name_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ ce = Z_OBJCE_P(zobject);
+ if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
+ if (ZEND_NUM_ARGS() > 1) {
+ if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE
+ || !instanceof_function(ce, *pce_cast TSRMLS_CC)
+ || !(*pce_cast)->get_iterator
+ ) {
+ zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ ce = *pce_cast;
+ }
+ if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
+ zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
+ if (EG(exception)) {
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implements Traversable", ce->name);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ zobject = retval;
+ ce = Z_OBJCE_P(zobject);
+ inc_refcount = 0;
+ }
+ }
+ break;
+ }
+ case DIT_AppendIterator:
+ spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
+ zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
+ intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return intern;
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ case DIT_RegexIterator:
+ case DIT_RecursiveRegexIterator: {
+ char *regex;
+ int regex_len;
+ long mode = REGIT_MODE_MATCH;
+
+ intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
+ intern->u.regex.flags = 0;
+ intern->u.regex.preg_flags = 0;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, &regex, &regex_len, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ if (mode < 0 || mode >= REGIT_MODE_MAX) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ intern->u.regex.mode = mode;
+ intern->u.regex.regex = estrndup(regex, regex_len);
+ intern->u.regex.regex_len = regex_len;
+ intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
+ if (intern->u.regex.pce == NULL) {
+ /* pcre_get_compiled_regex_cache has already sent error */
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ intern->u.regex.pce->refcount++;
+ break;
+ }
+#endif
+ case DIT_CallbackFilterIterator:
+ case DIT_RecursiveCallbackFilterIterator: {
+ _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi));
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ efree(cfi);
+ return NULL;
+ }
+ if (cfi->fci.function_name) {
+ Z_ADDREF_P(cfi->fci.function_name);
+ }
+ if (cfi->fci.object_ptr) {
+ Z_ADDREF_P(cfi->fci.object_ptr);
+ }
+ intern->u.cbfilter = cfi;
+ break;
+ }
+ default:
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return NULL;
+ }
+ break;
+ }
+
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+
+ if (inc_refcount) {
+ Z_ADDREF_P(zobject);
+ }
+ intern->inner.zobject = zobject;
+ intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
+ intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
+ intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
+
+ return intern;
+}
+
+/* {{{ proto void FilterIterator::__construct(Iterator it)
+ Create an Iterator from another iterator */
+SPL_METHOD(FilterIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
+} /* }}} */
+
+/* {{{ proto void CallbackFilterIterator::__construct(Iterator it, callback)
+ Create an Iterator from another iterator */
+SPL_METHOD(CallbackFilterIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator);
+} /* }}} */
+
+/* {{{ proto Iterator FilterIterator::getInnerIterator()
+ proto Iterator CachingIterator::getInnerIterator()
+ proto Iterator LimitIterator::getInnerIterator()
+ proto Iterator ParentIterator::getInnerIterator()
+ Get the inner iterator */
+SPL_METHOD(dual_it, getInnerIterator)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->inner.zobject) {
+ RETVAL_ZVAL(intern->inner.zobject, 1, 0);
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC)
+{
+ if (!intern->inner.iterator) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
+ }
+}
+
+static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
+{
+ if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
+ intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC);
+ }
+ if (intern->current.data) {
+ zval_ptr_dtor(&intern->current.data);
+ intern->current.data = NULL;
+ }
+ if (intern->current.str_key) {
+ efree(intern->current.str_key);
+ intern->current.str_key = NULL;
+ }
+ if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
+ if (intern->u.caching.zstr) {
+ zval_ptr_dtor(&intern->u.caching.zstr);
+ intern->u.caching.zstr = NULL;
+ }
+ if (intern->u.caching.zchildren) {
+ zval_ptr_dtor(&intern->u.caching.zchildren);
+ intern->u.caching.zchildren = NULL;
+ }
+ }
+}
+
+static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
+{
+ spl_dual_it_free(intern TSRMLS_CC);
+ intern->current.pos = 0;
+ if (intern->inner.iterator->funcs->rewind) {
+ intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
+ }
+}
+
+static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC)
+{
+ if (!intern->inner.iterator) {
+ return FAILURE;
+ }
+ /* FAILURE / SUCCESS */
+ return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC);
+}
+
+static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC)
+{
+ zval **data;
+
+ spl_dual_it_free(intern TSRMLS_CC);
+ if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
+ if (data && *data) {
+ intern->current.data = *data;
+ Z_ADDREF_P(intern->current.data);
+ }
+ if (intern->inner.iterator->funcs->get_current_key) {
+ intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC);
+ } else {
+ intern->current.key_type = HASH_KEY_IS_LONG;
+ intern->current.int_key = intern->current.pos;
+ }
+ return EG(exception) ? FAILURE : SUCCESS;
+ }
+ return FAILURE;
+}
+
+static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC)
+{
+ if (do_free) {
+ spl_dual_it_free(intern TSRMLS_CC);
+ } else {
+ spl_dual_it_require(intern TSRMLS_CC);
+ }
+ intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
+ intern->current.pos++;
+}
+
+/* {{{ proto void ParentIterator::rewind()
+ proto void IteratorIterator::rewind()
+ Rewind the iterator
+ */
+SPL_METHOD(dual_it, rewind)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ spl_dual_it_fetch(intern, 1 TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool FilterIterator::valid()
+ proto bool ParentIterator::valid()
+ proto bool IteratorIterator::valid()
+ proto bool NoRewindIterator::valid()
+ Check whether the current element is valid */
+SPL_METHOD(dual_it, valid)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_BOOL(intern->current.data);
+} /* }}} */
+
+/* {{{ proto mixed FilterIterator::key()
+ proto mixed CachingIterator::key()
+ proto mixed LimitIterator::key()
+ proto mixed ParentIterator::key()
+ proto mixed IteratorIterator::key()
+ proto mixed NoRewindIterator::key()
+ proto mixed AppendIterator::key()
+ Get the current key */
+SPL_METHOD(dual_it, key)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->current.data) {
+ if (intern->current.key_type == HASH_KEY_IS_STRING) {
+ RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
+ } else {
+ RETURN_LONG(intern->current.int_key);
+ }
+ }
+ RETURN_NULL();
+} /* }}} */
+
+/* {{{ proto mixed FilterIterator::current()
+ proto mixed CachingIterator::current()
+ proto mixed LimitIterator::current()
+ proto mixed ParentIterator::current()
+ proto mixed IteratorIterator::current()
+ proto mixed NoRewindIterator::current()
+ proto mixed AppendIterator::current()
+ Get the current element value */
+SPL_METHOD(dual_it, current)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->current.data) {
+ RETVAL_ZVAL(intern->current.data, 1, 0);
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+/* {{{ proto void ParentIterator::next()
+ proto void IteratorIterator::next()
+ proto void NoRewindIterator::next()
+ Move the iterator forward */
+SPL_METHOD(dual_it, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ spl_dual_it_fetch(intern, 1 TSRMLS_CC);
+} /* }}} */
+
+static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
+{
+ zval *retval;
+
+ while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
+ zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval);
+ if (retval) {
+ if (zend_is_true(retval)) {
+ zval_ptr_dtor(&retval);
+ return;
+ }
+ zval_ptr_dtor(&retval);
+ }
+ if (EG(exception)) {
+ return;
+ }
+ intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
+ }
+ spl_dual_it_free(intern TSRMLS_CC);
+}
+
+static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
+{
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ spl_filter_it_fetch(zthis, intern TSRMLS_CC);
+}
+
+static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
+{
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ spl_filter_it_fetch(zthis, intern TSRMLS_CC);
+}
+
+/* {{{ proto void FilterIterator::rewind()
+ Rewind the iterator */
+SPL_METHOD(FilterIterator, rewind)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ spl_filter_it_rewind(getThis(), intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void FilterIterator::next()
+ Move the iterator forward */
+SPL_METHOD(FilterIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ spl_filter_it_next(getThis(), intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void RecursiveCallbackFilterIterator::__construct(RecursiveIterator it, callback)
+ Create a RecursiveCallbackFilterIterator from a RecursiveIterator */
+SPL_METHOD(RecursiveCallbackFilterIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator);
+} /* }}} */
+
+
+/* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it)
+ Create a RecursiveFilterIterator from a RecursiveIterator */
+SPL_METHOD(RecursiveFilterIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
+} /* }}} */
+
+/* {{{ proto bool RecursiveFilterIterator::hasChildren()
+ Check whether the inner iterator's current element has children */
+SPL_METHOD(RecursiveFilterIterator, hasChildren)
+{
+ spl_dual_it_object *intern;
+ zval *retval;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ } else {
+ RETURN_FALSE;
+ }
+} /* }}} */
+
+/* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
+ Return the inner iterator's children contained in a RecursiveFilterIterator */
+SPL_METHOD(RecursiveFilterIterator, getChildren)
+{
+ spl_dual_it_object *intern;
+ zval *retval;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
+ if (!EG(exception) && retval) {
+ spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+} /* }}} */
+
+/* {{{ proto RecursiveCallbackFilterIterator RecursiveCallbackFilterIterator::getChildren()
+ Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */
+SPL_METHOD(RecursiveCallbackFilterIterator, getChildren)
+{
+ spl_dual_it_object *intern;
+ zval *retval;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
+ if (!EG(exception) && retval) {
+ spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, intern->u.cbfilter->fci.function_name TSRMLS_CC);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+} /* }}} */
+/* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
+ Create a ParentIterator from a RecursiveIterator */
+SPL_METHOD(ParentIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
+} /* }}} */
+
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+/* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]])
+ Create an RegexIterator from another iterator and a regular expression */
+SPL_METHOD(RegexIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
+} /* }}} */
+
+/* {{{ proto bool CallbackFilterIterator::accept()
+ Calls the callback with the current value, the current key and the inner iterator as arguments */
+SPL_METHOD(CallbackFilterIterator, accept)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zend_fcall_info *fci = &intern->u.cbfilter->fci;
+ zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc;
+ zval **params[3];
+ zval zkey;
+ zval *zkey_p = &zkey;
+ zval *result;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (intern->current.data == NULL) {
+ RETURN_FALSE;
+ }
+
+ INIT_PZVAL(&zkey);
+ if (intern->current.key_type == HASH_KEY_IS_LONG) {
+ ZVAL_LONG(&zkey, intern->current.int_key);
+ } else {
+ ZVAL_STRINGL(&zkey, intern->current.str_key, intern->current.str_key_len-1, 0);
+ }
+
+ params[0] = &intern->current.data;
+ params[1] = &zkey_p;
+ params[2] = &intern->inner.zobject;
+
+ fci->retval_ptr_ptr = &result;
+ fci->param_count = 3;
+ fci->params = params;
+ fci->no_separation = 0;
+
+ if (zend_call_function(fci, fcc TSRMLS_CC) != SUCCESS || !result) {
+ RETURN_FALSE;
+ }
+ if (EG(exception)) {
+ return;
+ }
+
+ RETURN_ZVAL(result, 1, 1);
+}
+/* }}} */
+
+/* {{{ proto bool RegexIterator::accept()
+ Match (string)current() against regular expression */
+SPL_METHOD(RegexIterator, accept)
+{
+ spl_dual_it_object *intern;
+ char *subject, tmp[32], *result;
+ int subject_len, use_copy, count = 0, result_len;
+ zval subject_copy, zcount, *replacement, tmp_replacement;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->current.data == NULL) {
+ RETURN_FALSE;
+ }
+
+ if (intern->u.regex.flags & REGIT_USE_KEY) {
+ if (intern->current.key_type == HASH_KEY_IS_LONG) {
+ subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
+ subject = &tmp[0];
+ use_copy = 0;
+ } else {
+ subject_len = intern->current.str_key_len - 1;
+ subject = estrndup(intern->current.str_key, subject_len);
+ use_copy = 1;
+ }
+ } else {
+ zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
+ if (use_copy) {
+ subject = Z_STRVAL(subject_copy);
+ subject_len = Z_STRLEN(subject_copy);
+ } else {
+ subject = Z_STRVAL_P(intern->current.data);
+ subject_len = Z_STRLEN_P(intern->current.data);
+ }
+ }
+
+ switch (intern->u.regex.mode)
+ {
+ case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
+ case REGIT_MODE_MATCH:
+ count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
+ RETVAL_BOOL(count >= 0);
+ break;
+
+ case REGIT_MODE_ALL_MATCHES:
+ case REGIT_MODE_GET_MATCH:
+ if (!use_copy) {
+ subject = estrndup(subject, subject_len);
+ use_copy = 1;
+ }
+ zval_ptr_dtor(&intern->current.data);
+ ALLOC_INIT_ZVAL(intern->current.data);
+ php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount,
+ intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
+ count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
+ RETVAL_BOOL(count > 0);
+ break;
+
+ case REGIT_MODE_SPLIT:
+ if (!use_copy) {
+ subject = estrndup(subject, subject_len);
+ use_copy = 1;
+ }
+ zval_ptr_dtor(&intern->current.data);
+ ALLOC_INIT_ZVAL(intern->current.data);
+ php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
+ count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
+ RETVAL_BOOL(count > 1);
+ break;
+
+ case REGIT_MODE_REPLACE:
+ replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
+ if (Z_TYPE_P(replacement) != IS_STRING) {
+ tmp_replacement = *replacement;
+ zval_copy_ctor(&tmp_replacement);
+ convert_to_string(&tmp_replacement);
+ replacement = &tmp_replacement;
+ }
+ result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
+
+ if (intern->u.regex.flags & REGIT_USE_KEY) {
+ if (intern->current.key_type != HASH_KEY_IS_LONG) {
+ efree(intern->current.str_key);
+ }
+ intern->current.key_type = HASH_KEY_IS_STRING;
+ intern->current.str_key = result;
+ intern->current.str_key_len = result_len + 1;
+ } else {
+ zval_ptr_dtor(&intern->current.data);
+ MAKE_STD_ZVAL(intern->current.data);
+ ZVAL_STRINGL(intern->current.data, result, result_len, 0);
+ }
+
+ if (replacement == &tmp_replacement) {
+ zval_dtor(replacement);
+ }
+ RETVAL_BOOL(count > 0);
+ }
+
+ if (intern->u.regex.flags & REGIT_INVERTED) {
+ RETVAL_BOOL(Z_LVAL_P(return_value));
+ }
+
+ if (use_copy) {
+ efree(subject);
+ }
+} /* }}} */
+
+/* {{{ proto string RegexIterator::getRegex()
+ Returns current regular expression */
+SPL_METHOD(RegexIterator, getRegex)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_STRINGL(intern->u.regex.regex, intern->u.regex.regex_len, 1);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getMode()
+ Returns current operation mode */
+SPL_METHOD(RegexIterator, getMode)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_LONG(intern->u.regex.mode);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setMode(int new_mode)
+ Set new operation mode */
+SPL_METHOD(RegexIterator, setMode)
+{
+ spl_dual_it_object *intern;
+ long mode;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
+ return;
+ }
+
+ if (mode < 0 || mode >= REGIT_MODE_MAX) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
+ return;/* NULL */
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ intern->u.regex.mode = mode;
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getFlags()
+ Returns current operation flags */
+SPL_METHOD(RegexIterator, getFlags)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_LONG(intern->u.regex.flags);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setFlags(int new_flags)
+ Set operation flags */
+SPL_METHOD(RegexIterator, setFlags)
+{
+ spl_dual_it_object *intern;
+ long flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ intern->u.regex.flags = flags;
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getFlags()
+ Returns current PREG flags (if in use or NULL) */
+SPL_METHOD(RegexIterator, getPregFlags)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->u.regex.use_flags) {
+ RETURN_LONG(intern->u.regex.preg_flags);
+ } else {
+ return;
+ }
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setPregFlags(int new_flags)
+ Set PREG flags */
+SPL_METHOD(RegexIterator, setPregFlags)
+{
+ spl_dual_it_object *intern;
+ long preg_flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ intern->u.regex.preg_flags = preg_flags;
+ intern->u.regex.use_flags = 1;
+} /* }}} */
+
+/* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]])
+ Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
+SPL_METHOD(RecursiveRegexIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
+} /* }}} */
+
+/* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
+ Return the inner iterator's children contained in a RecursiveRegexIterator */
+SPL_METHOD(RecursiveRegexIterator, getChildren)
+{
+ spl_dual_it_object *intern;
+ zval *retval, *regex;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
+ if (!EG(exception)) {
+ MAKE_STD_ZVAL(regex);
+ ZVAL_STRING(regex, intern->u.regex.regex, 1);
+ spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC);
+ zval_ptr_dtor(&regex);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+} /* }}} */
+
+#endif
+
+/* {{{ spl_dual_it_dtor */
+static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
+{
+ spl_dual_it_object *object = (spl_dual_it_object *)_object;
+
+ /* call standard dtor */
+ zend_objects_destroy_object(_object, handle TSRMLS_CC);
+
+ spl_dual_it_free(object TSRMLS_CC);
+
+ if (object->inner.iterator) {
+ object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ spl_dual_it_free_storage */
+static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
+{
+ spl_dual_it_object *object = (spl_dual_it_object *)_object;
+
+
+ if (object->inner.zobject) {
+ zval_ptr_dtor(&object->inner.zobject);
+ }
+
+ if (object->dit_type == DIT_AppendIterator) {
+ object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
+ if (object->u.append.zarrayit) {
+ zval_ptr_dtor(&object->u.append.zarrayit);
+ }
+ }
+
+ if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
+ if (object->u.caching.zcache) {
+ zval_ptr_dtor(&object->u.caching.zcache);
+ object->u.caching.zcache = NULL;
+ }
+ }
+
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
+ if (object->u.regex.pce) {
+ object->u.regex.pce->refcount--;
+ }
+ if (object->u.regex.regex) {
+ efree(object->u.regex.regex);
+ }
+ }
+#endif
+
+ if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) {
+ if (object->u.cbfilter) {
+ if (object->u.cbfilter->fci.function_name) {
+ zval_ptr_dtor(&object->u.cbfilter->fci.function_name);
+ }
+ if (object->u.cbfilter->fci.object_ptr) {
+ zval_ptr_dtor(&object->u.cbfilter->fci.object_ptr);
+ }
+ efree(object->u.cbfilter);
+ }
+ }
+
+ zend_object_std_dtor(&object->std TSRMLS_CC);
+
+ efree(object);
+}
+/* }}} */
+
+/* {{{ spl_dual_it_new */
+static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ zend_object_value retval;
+ spl_dual_it_object *intern;
+
+ intern = emalloc(sizeof(spl_dual_it_object));
+ memset(intern, 0, sizeof(spl_dual_it_object));
+ intern->dit_type = DIT_Unknown;
+
+ 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)spl_dual_it_dtor, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &spl_handlers_dual_it;
+ return retval;
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_FilterIterator[] = {
+ SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(FilterIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(FilterIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ABSTRACT_ME(FilterIterator, accept, arginfo_recursive_it_void)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO(arginfo_callback_filter_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, callback)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_CallbackFilterIterator[] = {
+ SPL_ME(CallbackFilterIterator, __construct, arginfo_callback_filter_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(CallbackFilterIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO(arginfo_recursive_callback_filter_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
+ ZEND_ARG_INFO(0, callback)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveCallbackFilterIterator[] = {
+ SPL_ME(RecursiveCallbackFilterIterator, __construct, arginfo_recursive_callback_filter_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveCallbackFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
+ SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_funcs_ParentIterator[] = {
+ SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
+ SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, regex)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1)
+ ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RegexIterator[] = {
+ SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getMode, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getPregFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getRegex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
+ ZEND_ARG_INFO(0, regex)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
+ SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveRegexIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+#endif
+
+static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
+{
+ /* FAILURE / SUCCESS */
+ if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
+ return FAILURE;
+ } else {
+ return spl_dual_it_valid(intern TSRMLS_CC);
+ }
+}
+
+static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC)
+{
+ zval *zpos;
+
+ spl_dual_it_free(intern TSRMLS_CC);
+ if (pos < intern->u.limit.offset) {
+ zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is below the offset %ld", pos, intern->u.limit.offset);
+ return;
+ }
+ if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
+ zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is behind offset %ld plus count %ld", pos, intern->u.limit.offset, intern->u.limit.count);
+ return;
+ }
+ if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) {
+ MAKE_STD_ZVAL(zpos);
+ ZVAL_LONG(zpos, pos);
+ spl_dual_it_free(intern TSRMLS_CC);
+ zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
+ zval_ptr_dtor(&zpos);
+ if (!EG(exception)) {
+ intern->current.pos = pos;
+ if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+ }
+ }
+ } else {
+ /* emulate the forward seek, by next() calls */
+ /* a back ward seek is done by a previous rewind() */
+ if (pos < intern->current.pos) {
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ }
+ while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ }
+ if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_fetch(intern, 1 TSRMLS_CC);
+ }
+ }
+}
+
+/* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count])
+ Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
+SPL_METHOD(LimitIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
+} /* }}} */
+
+/* {{{ proto void LimitIterator::rewind()
+ Rewind the iterator to the specified starting offset */
+SPL_METHOD(LimitIterator, rewind)
+{
+ spl_dual_it_object *intern;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool LimitIterator::valid()
+ Check whether the current element is valid */
+SPL_METHOD(LimitIterator, valid)
+{
+ spl_dual_it_object *intern;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+/* RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/
+ RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data);
+} /* }}} */
+
+/* {{{ proto void LimitIterator::next()
+ Move the iterator forward */
+SPL_METHOD(LimitIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
+ spl_dual_it_fetch(intern, 1 TSRMLS_CC);
+ }
+} /* }}} */
+
+/* {{{ proto void LimitIterator::seek(int position)
+ Seek to the given position */
+SPL_METHOD(LimitIterator, seek)
+{
+ spl_dual_it_object *intern;
+ long pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ spl_limit_it_seek(intern, pos TSRMLS_CC);
+ RETURN_LONG(intern->current.pos);
+} /* }}} */
+
+/* {{{ proto int LimitIterator::getPosition()
+ Return the current position */
+SPL_METHOD(LimitIterator, getPosition)
+{
+ spl_dual_it_object *intern;
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ RETURN_LONG(intern->current.pos);
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0)
+ ZEND_ARG_INFO(0, position)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_SeekableIterator[] = {
+ SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
+ PHP_FE_END
+};
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, offset)
+ ZEND_ARG_INFO(0, count)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0)
+ ZEND_ARG_INFO(0, position)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_LimitIterator[] = {
+ SPL_ME(LimitIterator, __construct, arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(LimitIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(LimitIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(LimitIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(LimitIterator, seek, arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
+ SPL_ME(LimitIterator, getPosition, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC)
+{
+ return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
+}
+
+static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC)
+{
+ return spl_dual_it_valid(intern TSRMLS_CC);
+}
+
+static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
+{
+ if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
+ intern->u.caching.flags |= CIT_VALID;
+ /* Full cache ? */
+ if (intern->u.caching.flags & CIT_FULL_CACHE) {
+ zval *zcacheval;
+
+ MAKE_STD_ZVAL(zcacheval);
+ ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
+ if (intern->current.key_type == HASH_KEY_IS_LONG) {
+ add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
+ } else {
+ zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
+ }
+ }
+ /* Recursion ? */
+ if (intern->dit_type == DIT_RecursiveCachingIterator) {
+ zval *retval, *zchildren, zflags;
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
+ if (EG(exception)) {
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ zend_clear_exception(TSRMLS_C);
+ } else {
+ return;
+ }
+ } else {
+ if (zend_is_true(retval)) {
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
+ if (EG(exception)) {
+ if (zchildren) {
+ zval_ptr_dtor(&zchildren);
+ }
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ zend_clear_exception(TSRMLS_C);
+ } else {
+ zval_ptr_dtor(&retval);
+ return;
+ }
+ } else {
+ INIT_PZVAL(&zflags);
+ ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
+ spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
+ zval_ptr_dtor(&zchildren);
+ }
+ }
+ zval_ptr_dtor(&retval);
+ if (EG(exception)) {
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ zend_clear_exception(TSRMLS_C);
+ } else {
+ return;
+ }
+ }
+ }
+ }
+ if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
+ int use_copy;
+ zval expr_copy;
+ ALLOC_ZVAL(intern->u.caching.zstr);
+ if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
+ *intern->u.caching.zstr = *intern->inner.zobject;
+ } else {
+ *intern->u.caching.zstr = *intern->current.data;
+ }
+ zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
+ if (use_copy) {
+ *intern->u.caching.zstr = expr_copy;
+ INIT_PZVAL(intern->u.caching.zstr);
+ zval_copy_ctor(intern->u.caching.zstr);
+ zval_dtor(&expr_copy);
+ } else {
+ INIT_PZVAL(intern->u.caching.zstr);
+ zval_copy_ctor(intern->u.caching.zstr);
+ }
+ }
+ spl_dual_it_next(intern, 0 TSRMLS_CC);
+ } else {
+ intern->u.caching.flags &= ~CIT_VALID;
+ }
+}
+
+static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
+{
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ zend_hash_clean(HASH_OF(intern->u.caching.zcache));
+ spl_caching_it_next(intern TSRMLS_CC);
+}
+
+/* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING])
+ Construct a CachingIterator from an Iterator */
+SPL_METHOD(CachingIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
+} /* }}} */
+
+/* {{{ proto void CachingIterator::rewind()
+ Rewind the iterator */
+SPL_METHOD(CachingIterator, rewind)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_caching_it_rewind(intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool CachingIterator::valid()
+ Check whether the current element is valid */
+SPL_METHOD(CachingIterator, valid)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS);
+} /* }}} */
+
+/* {{{ proto void CachingIterator::next()
+ Move the iterator forward */
+SPL_METHOD(CachingIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_caching_it_next(intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool CachingIterator::hasNext()
+ Check whether the inner iterator has a valid next element */
+SPL_METHOD(CachingIterator, hasNext)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS);
+} /* }}} */
+
+/* {{{ proto string CachingIterator::__toString()
+ Return the string representation of the current element */
+SPL_METHOD(CachingIterator, __toString)
+{
+ spl_dual_it_object *intern;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+ if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
+ if (intern->current.key_type == HASH_KEY_IS_STRING) {
+ RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
+ } else {
+ RETVAL_LONG(intern->current.int_key);
+ convert_to_string(return_value);
+ return;
+ }
+ } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
+ MAKE_COPY_ZVAL(&intern->current.data, return_value);
+ convert_to_string(return_value);
+ return;
+ }
+ if (intern->u.caching.zstr) {
+ RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1);
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+/* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
+ Set given index in cache */
+SPL_METHOD(CachingIterator, offsetSet)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+ zval *value;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
+ return;
+ }
+
+ Z_ADDREF_P(value);
+ zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
+}
+/* }}} */
+
+/* {{{ proto string CachingIterator::offsetGet(mixed index)
+ Return the internal cache if used */
+SPL_METHOD(CachingIterator, offsetGet)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+ zval **value;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
+ zend_error(E_NOTICE, "Undefined index: %s", arKey);
+ return;
+ }
+
+ RETURN_ZVAL(*value, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto void CachingIterator::offsetUnset(mixed index)
+ Unset given index in cache */
+SPL_METHOD(CachingIterator, offsetUnset)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
+}
+/* }}} */
+
+/* {{{ proto bool CachingIterator::offsetExists(mixed index)
+ Return whether the requested index exists */
+SPL_METHOD(CachingIterator, offsetExists)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
+}
+/* }}} */
+
+/* {{{ proto bool CachingIterator::getCache()
+ Return the cache */
+SPL_METHOD(CachingIterator, getCache)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto int CachingIterator::getFlags()
+ Return the internal flags */
+SPL_METHOD(CachingIterator, getFlags)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_LONG(intern->u.caching.flags);
+}
+/* }}} */
+
+/* {{{ proto void CachingIterator::setFlags(int flags)
+ Set the internal flags */
+SPL_METHOD(CachingIterator, setFlags)
+{
+ spl_dual_it_object *intern;
+ long flags;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
+ return;
+ }
+
+ if (spl_cit_check_flags(flags) != SUCCESS) {
+ zend_throw_exception(spl_ce_InvalidArgumentException , "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0 TSRMLS_CC);
+ return;
+ }
+ if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
+ return;
+ }
+ if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
+ return;
+ }
+ if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
+ /* clear on (re)enable */
+ zend_hash_clean(HASH_OF(intern->u.caching.zcache));
+ }
+ intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
+}
+/* }}} */
+
+/* {{{ proto void CachingIterator::count()
+ Number of cached elements */
+SPL_METHOD(CachingIterator, count)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache)));
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_CachingIterator[] = {
+ SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, hasNext, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, __toString, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, getCache, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, count, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING])
+ Create an iterator from a RecursiveIterator */
+SPL_METHOD(RecursiveCachingIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
+} /* }}} */
+
+/* {{{ proto bool RecursiveCachingIterator::hasChildren()
+ Check whether the current element of the inner iterator has children */
+SPL_METHOD(RecursiveCachingIterator, hasChildren)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_BOOL(intern->u.caching.zchildren);
+} /* }}} */
+
+/* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren()
+ Return the inner iterator's children as a RecursiveCachingIterator */
+SPL_METHOD(RecursiveCachingIterator, getChildren)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->u.caching.zchildren) {
+ RETURN_ZVAL(intern->u.caching.zchildren, 1, 0);
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
+ SPL_ME(RecursiveCachingIterator, __construct, arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveCachingIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveCachingIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* {{{ proto void IteratorIterator::__construct(Traversable it)
+ Create an iterator from anything that is traversable */
+SPL_METHOD(IteratorIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_IteratorIterator[] = {
+ SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* {{{ proto void NoRewindIterator::__construct(Iterator it)
+ Create an iterator from another iterator */
+SPL_METHOD(NoRewindIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
+} /* }}} */
+
+/* {{{ proto void NoRewindIterator::rewind()
+ Prevent a call to inner iterators rewind() */
+SPL_METHOD(NoRewindIterator, rewind)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ /* nothing to do */
+} /* }}} */
+
+/* {{{ proto bool NoRewindIterator::valid()
+ Return inner iterators valid() */
+SPL_METHOD(NoRewindIterator, valid)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS);
+} /* }}} */
+
+/* {{{ proto mixed NoRewindIterator::key()
+ Return inner iterators key() */
+SPL_METHOD(NoRewindIterator, key)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (intern->inner.iterator->funcs->get_current_key) {
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+ switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
+ case HASH_KEY_IS_LONG:
+ RETURN_LONG(int_key);
+ break;
+ case HASH_KEY_IS_STRING:
+ RETURN_STRINGL(str_key, str_key_len-1, 0);
+ break;
+ default:
+ RETURN_NULL();
+ }
+ } else {
+ RETURN_NULL();
+ }
+} /* }}} */
+
+/* {{{ proto mixed NoRewindIterator::current()
+ Return inner iterators current() */
+SPL_METHOD(NoRewindIterator, current)
+{
+ spl_dual_it_object *intern;
+ zval **data;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
+ if (data && *data) {
+ RETURN_ZVAL(*data, 1, 0);
+ }
+} /* }}} */
+
+/* {{{ proto void NoRewindIterator::next()
+ Return inner iterators next() */
+SPL_METHOD(NoRewindIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+ intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_NoRewindIterator[] = {
+ SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(NoRewindIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(NoRewindIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(NoRewindIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(NoRewindIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(NoRewindIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* {{{ proto void InfiniteIterator::__construct(Iterator it)
+ Create an iterator from another iterator */
+SPL_METHOD(InfiniteIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
+} /* }}} */
+
+/* {{{ proto void InfiniteIterator::next()
+ Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
+SPL_METHOD(InfiniteIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+ } else {
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+ }
+ }
+} /* }}} */
+
+static const zend_function_entry spl_funcs_InfiniteIterator[] = {
+ SPL_ME(InfiniteIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(InfiniteIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/* {{{ proto void EmptyIterator::rewind()
+ Does nothing */
+SPL_METHOD(EmptyIterator, rewind)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+} /* }}} */
+
+/* {{{ proto false EmptyIterator::valid()
+ Return false */
+SPL_METHOD(EmptyIterator, valid)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto void EmptyIterator::key()
+ Throws exception BadMethodCallException */
+SPL_METHOD(EmptyIterator, key)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void EmptyIterator::current()
+ Throws exception BadMethodCallException */
+SPL_METHOD(EmptyIterator, current)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void EmptyIterator::next()
+ Does nothing */
+SPL_METHOD(EmptyIterator, next)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+} /* }}} */
+
+static const zend_function_entry spl_funcs_EmptyIterator[] = {
+ SPL_ME(EmptyIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(EmptyIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(EmptyIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(EmptyIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(EmptyIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
+{
+ spl_dual_it_free(intern TSRMLS_CC);
+
+ if (intern->inner.zobject) {
+ zval_ptr_dtor(&intern->inner.zobject);
+ intern->inner.zobject = NULL;
+ intern->inner.ce = NULL;
+ intern->inner.object = NULL;
+ if (intern->inner.iterator) {
+ intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC);
+ intern->inner.iterator = NULL;
+ }
+ }
+ if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) {
+ zval **it;
+
+ intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC);
+ Z_ADDREF_PP(it);
+ intern->inner.zobject = *it;
+ intern->inner.ce = Z_OBJCE_PP(it);
+ intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
+ intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
+ spl_dual_it_rewind(intern TSRMLS_CC);
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+} /* }}} */
+
+void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
+{
+ while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
+ intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC);
+ if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) {
+ return;
+ }
+ }
+ spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+} /* }}} */
+
+void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_next(intern, 1 TSRMLS_CC);
+ }
+ spl_append_it_fetch(intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void AppendIterator::__construct()
+ Create an AppendIterator */
+SPL_METHOD(AppendIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
+} /* }}} */
+
+/* {{{ proto void AppendIterator::append(Iterator it)
+ Append an iterator */
+SPL_METHOD(AppendIterator, append)
+{
+ spl_dual_it_object *intern;
+ zval *it;
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
+ return;
+ }
+ spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
+
+ if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
+ if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) {
+ intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
+ }
+ do {
+ spl_append_it_next_iterator(intern TSRMLS_CC);
+ } while (intern->inner.zobject != it);
+ spl_append_it_fetch(intern TSRMLS_CC);
+ }
+} /* }}} */
+
+/* {{{ proto void AppendIterator::rewind()
+ Rewind to the first iterator and rewind the first iterator, too */
+SPL_METHOD(AppendIterator, rewind)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
+ if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) {
+ spl_append_it_fetch(intern TSRMLS_CC);
+ }
+} /* }}} */
+
+/* {{{ proto bool AppendIterator::valid()
+ Check if the current state is valid */
+SPL_METHOD(AppendIterator, valid)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_BOOL(intern->current.data);
+} /* }}} */
+
+/* {{{ proto void AppendIterator::next()
+ Forward to next element */
+SPL_METHOD(AppendIterator, next)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ spl_append_it_next(intern TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto int AppendIterator::getIteratorIndex()
+ Get index of iterator */
+SPL_METHOD(AppendIterator, getIteratorIndex)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ APPENDIT_CHECK_CTOR(intern);
+ spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
+ Get access to inner ArrayIterator */
+SPL_METHOD(AppendIterator, getArrayIterator)
+{
+ spl_dual_it_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
+
+ RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_AppendIterator[] = {
+ SPL_ME(AppendIterator, __construct, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, append, arginfo_append_it_append, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
+{
+ zend_object_iterator *iter;
+ zend_class_entry *ce = Z_OBJCE_P(obj);
+
+ iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
+
+ if (EG(exception)) {
+ goto done;
+ }
+
+ iter->index = 0;
+ if (iter->funcs->rewind) {
+ iter->funcs->rewind(iter TSRMLS_CC);
+ if (EG(exception)) {
+ goto done;
+ }
+ }
+
+ while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
+ if (EG(exception)) {
+ goto done;
+ }
+ if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
+ goto done;
+ }
+ iter->index++;
+ iter->funcs->move_forward(iter TSRMLS_CC);
+ if (EG(exception)) {
+ goto done;
+ }
+ }
+
+done:
+ if (iter) {
+ iter->funcs->dtor(iter TSRMLS_CC);
+ }
+ return EG(exception) ? FAILURE : SUCCESS;
+}
+/* }}} */
+
+static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval **data, *return_value = (zval*)puser;
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+ int key_type;
+
+ iter->funcs->get_current_data(iter, &data TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (data == NULL || *data == NULL) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (iter->funcs->get_current_key) {
+ key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ Z_ADDREF_PP(data);
+ switch(key_type) {
+ case HASH_KEY_IS_STRING:
+ add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
+ efree(str_key);
+ break;
+ case HASH_KEY_IS_LONG:
+ add_index_zval(return_value, int_key, *data);
+ break;
+ }
+ } else {
+ Z_ADDREF_PP(data);
+ add_next_index_zval(return_value, *data);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval **data, *return_value = (zval*)puser;
+
+ iter->funcs->get_current_data(iter, &data TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (data == NULL || *data == NULL) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ Z_ADDREF_PP(data);
+ add_next_index_zval(return_value, *data);
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true])
+ Copy the iterator into an array */
+PHP_FUNCTION(iterator_to_array)
+{
+ zval *obj;
+ zend_bool use_keys = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+} /* }}} */
+
+static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ (*(long*)puser)++;
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* {{{ proto int iterator_count(Traversable it)
+ Count the elements in an iterator */
+PHP_FUNCTION(iterator_count)
+{
+ zval *obj;
+ long count = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
+ RETURN_LONG(count);
+ }
+}
+/* }}} */
+
+typedef struct {
+ zval *obj;
+ zval *args;
+ long count;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+} spl_iterator_apply_info;
+
+static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval *retval;
+ spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser;
+ int result;
+
+ apply_info->count++;
+ zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
+ if (retval) {
+ result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
+ zval_ptr_dtor(&retval);
+ } else {
+ result = ZEND_HASH_APPLY_STOP;
+ }
+ return result;
+}
+/* }}} */
+
+/* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
+ Calls a function for every element in an iterator */
+PHP_FUNCTION(iterator_apply)
+{
+ spl_iterator_apply_info apply_info;
+
+ apply_info.args = NULL;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
+ return;
+ }
+
+ apply_info.count = 0;
+ zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
+ if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
+ RETVAL_LONG(apply_info.count);
+ } else {
+ RETVAL_FALSE;
+ }
+ zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
+}
+/* }}} */
+
+static const zend_function_entry spl_funcs_OuterIterator[] = {
+ SPL_ABSTRACT_ME(OuterIterator, getInnerIterator, arginfo_recursive_it_void)
+ PHP_FE_END
+};
+
+static const zend_function_entry spl_funcs_Countable[] = {
+ SPL_ABSTRACT_ME(Countable, count, arginfo_recursive_it_void)
+ PHP_FE_END
+};
+
+/* {{{ PHP_MINIT_FUNCTION(spl_iterators)
+ */
+PHP_MINIT_FUNCTION(spl_iterators)
+{
+ REGISTER_SPL_INTERFACE(RecursiveIterator);
+ REGISTER_SPL_ITERATOR(RecursiveIterator);
+
+ REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
+ REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
+
+ 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;
+
+ 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_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
+ spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
+
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
+
+ REGISTER_SPL_INTERFACE(OuterIterator);
+ REGISTER_SPL_ITERATOR(OuterIterator);
+
+ REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
+ REGISTER_SPL_ITERATOR(IteratorIterator);
+ REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
+ spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(CallbackFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_CallbackFilterIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveCallbackFilterIterator, CallbackFilterIterator, spl_dual_it_new, spl_funcs_RecursiveCallbackFilterIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveCallbackFilterIterator, RecursiveIterator);
+
+
+ REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
+
+ REGISTER_SPL_INTERFACE(Countable);
+ REGISTER_SPL_INTERFACE(SeekableIterator);
+ REGISTER_SPL_ITERATOR(SeekableIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
+ REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
+ REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
+
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE);
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
+
+ REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE);
+ REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
+#else
+ spl_ce_RegexIterator = NULL;
+ spl_ce_RecursiveRegexIterator = NULL;
+#endif
+
+ REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
+ REGISTER_SPL_ITERATOR(EmptyIterator);
+
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT", RTIT_BYPASS_CURRENT);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY", RTIT_BYPASS_KEY);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT", 0);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 2);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 4);
+ REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT", 5);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
new file mode 100644
index 0000000..39cc0d1
--- /dev/null
+++ b/ext/spl/spl_iterators.h
@@ -0,0 +1,186 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_ITERATORS_H
+#define SPL_ITERATORS_H
+
+#include "php.h"
+#include "php_spl.h"
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+#include "ext/pcre/php_pcre.h"
+#endif
+
+#define spl_ce_Traversable zend_ce_traversable
+#define spl_ce_Iterator zend_ce_iterator
+#define spl_ce_Aggregate zend_ce_aggregate
+#define spl_ce_ArrayAccess zend_ce_arrayaccess
+#define spl_ce_Serializable zend_ce_serializable
+
+extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
+extern PHPAPI zend_class_entry *spl_ce_FilterIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
+extern PHPAPI zend_class_entry *spl_ce_ParentIterator;
+extern PHPAPI zend_class_entry *spl_ce_SeekableIterator;
+extern PHPAPI zend_class_entry *spl_ce_LimitIterator;
+extern PHPAPI zend_class_entry *spl_ce_CachingIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
+extern PHPAPI zend_class_entry *spl_ce_OuterIterator;
+extern PHPAPI zend_class_entry *spl_ce_IteratorIterator;
+extern PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
+extern PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
+extern PHPAPI zend_class_entry *spl_ce_EmptyIterator;
+extern PHPAPI zend_class_entry *spl_ce_AppendIterator;
+extern PHPAPI zend_class_entry *spl_ce_RegexIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
+extern PHPAPI zend_class_entry *spl_ce_Countable;
+extern PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator;
+
+PHP_MINIT_FUNCTION(spl_iterators);
+
+PHP_FUNCTION(iterator_to_array);
+PHP_FUNCTION(iterator_count);
+PHP_FUNCTION(iterator_apply);
+
+typedef enum {
+ DIT_Default = 0,
+ DIT_FilterIterator = DIT_Default,
+ DIT_RecursiveFilterIterator = DIT_Default,
+ DIT_ParentIterator = DIT_Default,
+ DIT_LimitIterator,
+ DIT_CachingIterator,
+ DIT_RecursiveCachingIterator,
+ DIT_IteratorIterator,
+ DIT_NoRewindIterator,
+ DIT_InfiniteIterator,
+ DIT_AppendIterator,
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ DIT_RegexIterator,
+ DIT_RecursiveRegexIterator,
+#endif
+ DIT_CallbackFilterIterator,
+ DIT_RecursiveCallbackFilterIterator,
+ DIT_Unknown = ~0
+} dual_it_type;
+
+typedef enum {
+ RIT_Default = 0,
+ RIT_RecursiveIteratorIterator = RIT_Default,
+ RIT_RecursiveTreeIterator,
+ RIT_Unknow = ~0
+} recursive_it_it_type;
+
+enum {
+ /* public */
+ CIT_CALL_TOSTRING = 0x00000001,
+ CIT_TOSTRING_USE_KEY = 0x00000002,
+ CIT_TOSTRING_USE_CURRENT = 0x00000004,
+ CIT_TOSTRING_USE_INNER = 0x00000008,
+ CIT_CATCH_GET_CHILD = 0x00000010,
+ CIT_FULL_CACHE = 0x00000100,
+ CIT_PUBLIC = 0x0000FFFF,
+ /* private */
+ CIT_VALID = 0x00010000,
+ CIT_HAS_CHILDREN = 0x00020000
+};
+
+enum {
+ /* public */
+ REGIT_USE_KEY = 0x00000001,
+ REGIT_INVERTED = 0x00000002
+};
+
+typedef enum {
+ REGIT_MODE_MATCH,
+ REGIT_MODE_GET_MATCH,
+ REGIT_MODE_ALL_MATCHES,
+ REGIT_MODE_SPLIT,
+ REGIT_MODE_REPLACE,
+ REGIT_MODE_MAX
+} regex_mode;
+
+typedef struct _spl_cbfilter_it_intern {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+} _spl_cbfilter_it_intern;
+
+typedef struct _spl_dual_it_object {
+ zend_object std;
+ struct {
+ zval *zobject;
+ zend_class_entry *ce;
+ zend_object *object;
+ zend_object_iterator *iterator;
+ } inner;
+ struct {
+ zval *data;
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+ int key_type; /* HASH_KEY_IS_STRING or HASH_KEY_IS_LONG */
+ int pos;
+ } current;
+ dual_it_type dit_type;
+ union {
+ struct {
+ long offset;
+ long count;
+ } limit;
+ struct {
+ long flags; /* CIT_* */
+ zval *zstr;
+ zval *zchildren;
+ zval *zcache;
+ } caching;
+ struct {
+ zval *zarrayit;
+ zend_object_iterator *iterator;
+ } append;
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ struct {
+ int use_flags;
+ long flags;
+ regex_mode mode;
+ long preg_flags;
+ pcre_cache_entry *pce;
+ char *regex;
+ uint regex_len;
+ } regex;
+#endif
+ _spl_cbfilter_it_intern *cbfilter;
+ } u;
+} spl_dual_it_object;
+
+typedef int (*spl_iterator_apply_func_t)(zend_object_iterator *iter, void *puser TSRMLS_DC);
+
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC);
+
+#endif /* SPL_ITERATORS_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
new file mode 100644
index 0000000..5d89566
--- /dev/null
+++ b/ext/spl/spl_observer.c
@@ -0,0 +1,1341 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ | Etienne Kneuss <colder@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/php_smart_str.h"
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_observer.h"
+#include "spl_iterators.h"
+#include "spl_array.h"
+#include "spl_exceptions.h"
+
+SPL_METHOD(SplObserver, update);
+SPL_METHOD(SplSubject, attach);
+SPL_METHOD(SplSubject, detach);
+SPL_METHOD(SplSubject, notify);
+
+ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0)
+ ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_SplObserver[] = {
+ SPL_ABSTRACT_ME(SplObserver, update, arginfo_SplObserver_update)
+ {NULL, NULL, NULL}
+};
+
+ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0)
+ ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_void, 0)
+ZEND_END_ARG_INFO();
+
+/*ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1)
+ZEND_END_ARG_INFO();*/
+
+static const zend_function_entry spl_funcs_SplSubject[] = {
+ SPL_ABSTRACT_ME(SplSubject, attach, arginfo_SplSubject_attach)
+ SPL_ABSTRACT_ME(SplSubject, detach, arginfo_SplSubject_attach)
+ SPL_ABSTRACT_ME(SplSubject, notify, arginfo_SplSubject_void)
+ {NULL, NULL, NULL}
+};
+
+PHPAPI zend_class_entry *spl_ce_SplObserver;
+PHPAPI zend_class_entry *spl_ce_SplSubject;
+PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
+PHPAPI zend_class_entry *spl_ce_MultipleIterator;
+
+PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
+
+typedef struct _spl_SplObjectStorage { /* {{{ */
+ zend_object std;
+ HashTable storage;
+ long index;
+ HashPosition pos;
+ long flags;
+ zend_function *fptr_get_hash;
+ HashTable *debug_info;
+} spl_SplObjectStorage; /* }}} */
+
+/* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
+typedef struct _spl_SplObjectStorageElement {
+ zval* obj;
+ zval* inf;
+} spl_SplObjectStorageElement; /* }}} */
+
+void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
+
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+
+ zend_hash_destroy(&intern->storage);
+
+ if (intern->debug_info != NULL) {
+ zend_hash_destroy(intern->debug_info);
+ efree(intern->debug_info);
+ }
+
+ efree(object);
+} /* }}} */
+
+static char *spl_object_storage_get_hash(spl_SplObjectStorage *intern, zval *this, zval *obj, int *hash_len_ptr TSRMLS_DC) {
+ if (intern->fptr_get_hash) {
+ zval *rv;
+ zend_call_method_with_1_params(&this, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, obj);
+ if (rv) {
+ if (Z_TYPE_P(rv) == IS_STRING) {
+ int hash_len = Z_STRLEN_P(rv);
+ char *hash = emalloc((hash_len+1)*sizeof(char));
+ strncpy(hash, Z_STRVAL_P(rv), hash_len);
+ hash[hash_len] = 0;
+
+ zval_ptr_dtor(&rv);
+ if (hash_len_ptr) {
+ *hash_len_ptr = hash_len;
+ }
+ return hash;
+ } else {
+ zend_throw_exception(spl_ce_RuntimeException, "Hash needs to be a string", 0 TSRMLS_CC);
+
+ zval_ptr_dtor(&rv);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ } else {
+ int hash_len = sizeof(zend_object_value);
+
+#if HAVE_PACKED_OBJECT_VALUE
+
+ if (hash_len_ptr) {
+ *hash_len_ptr = hash_len;
+ }
+
+ return (char*)&Z_OBJVAL_P(obj);
+#else
+ char *hash = emalloc(hash_len + 1);
+
+ zend_object_value zvalue;
+ memset(&zvalue, 0, sizeof(zend_object_value));
+ zvalue.handle = Z_OBJ_HANDLE_P(obj);
+ zvalue.handlers = Z_OBJ_HT_P(obj);
+
+ memcpy(hash, (char *)&zvalue, hash_len);
+ hash[hash_len] = 0;
+
+ if (hash_len_ptr) {
+ *hash_len_ptr = hash_len;
+ }
+
+ return hash;
+#endif
+ }
+}
+
+static void spl_object_storage_free_hash(spl_SplObjectStorage *intern, char *hash) {
+ if (intern->fptr_get_hash) {
+ efree(hash);
+ } else {
+#if HAVE_PACKED_OBJECT_VALUE
+ /* Nothing to do */
+#else
+ efree(hash);
+#endif
+ }
+}
+
+static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */
+{
+ zval_ptr_dtor(&element->obj);
+ zval_ptr_dtor(&element->inf);
+} /* }}} */
+
+spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, char *hash, int hash_len TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorageElement *element;
+ if (zend_hash_find(&intern->storage, hash, hash_len, (void**)&element) == SUCCESS) {
+ return element;
+ } else {
+ return NULL;
+ }
+} /* }}} */
+
+void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *this, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorageElement *pelement, element;
+
+ int hash_len;
+ char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+ if (!hash) {
+ return;
+ }
+
+ pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+
+ if (inf) {
+ Z_ADDREF_P(inf);
+ } else {
+ ALLOC_INIT_ZVAL(inf);
+ }
+ if (pelement) {
+ zval_ptr_dtor(&pelement->inf);
+ pelement->inf = inf;
+ spl_object_storage_free_hash(intern, hash);
+ return;
+ }
+ Z_ADDREF_P(obj);
+ element.obj = obj;
+ element.inf = inf;
+ zend_hash_update(&intern->storage, hash, hash_len, &element, sizeof(spl_SplObjectStorageElement), NULL);
+ spl_object_storage_free_hash(intern, hash);
+} /* }}} */
+
+int spl_object_storage_detach(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */
+{
+ int hash_len, ret = FAILURE;
+ char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+ if (!hash) {
+ return ret;
+ }
+ ret = zend_hash_del(&intern->storage, hash, hash_len);
+ spl_object_storage_free_hash(intern, hash);
+
+ return ret;
+} /* }}}*/
+
+void spl_object_storage_addall(spl_SplObjectStorage *intern, zval *this, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
+ HashPosition pos;
+ spl_SplObjectStorageElement *element;
+
+ zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
+ while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
+ spl_object_storage_attach(intern, this, element->obj, element->inf TSRMLS_CC);
+ zend_hash_move_forward_ex(&other->storage, &pos);
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ intern->index = 0;
+} /* }}} */
+
+static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
+{
+ zend_object_value retval;
+ spl_SplObjectStorage *intern;
+ zend_class_entry *parent = class_type;
+
+ intern = emalloc(sizeof(spl_SplObjectStorage));
+ memset(intern, 0, sizeof(spl_SplObjectStorage));
+ *obj = intern;
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0);
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &spl_handler_SplObjectStorage;
+
+ if (orig) {
+ spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC);
+ spl_object_storage_addall(intern, orig, other TSRMLS_CC);
+ }
+
+ while (parent) {
+ if (parent == spl_ce_SplObjectStorage) {
+ if (class_type != spl_ce_SplObjectStorage) {
+ zend_hash_find(&class_type->function_table, "gethash", sizeof("gethash"), (void **) &intern->fptr_get_hash);
+ if (intern->fptr_get_hash->common.scope == spl_ce_SplObjectStorage) {
+ intern->fptr_get_hash = NULL;
+ }
+ }
+ break;
+ }
+
+ parent = parent->parent;
+ }
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ spl_object_storage_clone */
+static zend_object_value spl_object_storage_clone(zval *zobject TSRMLS_DC)
+{
+ zend_object_value new_obj_val;
+ zend_object *old_object;
+ zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
+ spl_SplObjectStorage *intern;
+
+ old_object = zend_objects_get_address(zobject TSRMLS_CC);
+ new_obj_val = spl_object_storage_new_ex(old_object->ce, &intern, zobject TSRMLS_CC);
+ new_object = &intern->std;
+
+ zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
+
+ return new_obj_val;
+}
+/* }}} */
+
+static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
+ spl_SplObjectStorageElement *element;
+ HashTable *props;
+ HashPosition pos;
+ zval *tmp, *storage;
+ char md5str[33];
+ int name_len;
+ char *zname;
+
+ *is_temp = 0;
+
+ props = Z_OBJPROP_P(obj);
+ zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
+
+ if (intern->debug_info == NULL) {
+ ALLOC_HASHTABLE(intern->debug_info);
+ ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0);
+ }
+
+ if (intern->debug_info->nApplyCount == 0) {
+ zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ MAKE_STD_ZVAL(storage);
+ array_init(storage);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
+ php_spl_object_hash(element->obj, md5str TSRMLS_CC);
+ MAKE_STD_ZVAL(tmp);
+ array_init(tmp);
+ /* Incrementing the refcount of obj and inf would confuse the garbage collector.
+ * Prefer to null the destructor */
+ Z_ARRVAL_P(tmp)->pDestructor = NULL;
+ add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj);
+ add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf);
+ add_assoc_zval_ex(storage, md5str, 33, tmp);
+ zend_hash_move_forward_ex(&intern->storage, &pos);
+ }
+
+ zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
+ zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
+ efree(zname);
+ }
+
+ return intern->debug_info;
+}
+/* }}} */
+
+/* overriden for garbage collection
+ * This is very hacky */
+static HashTable *spl_object_storage_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
+ spl_SplObjectStorageElement *element;
+ HashTable *props;
+ HashPosition pos;
+ zval *gcdata_arr = NULL,
+ **gcdata_arr_pp;
+
+ props = std_object_handlers.get_properties(obj TSRMLS_CC);
+
+ *table = NULL;
+ *n = 0;
+
+ /* clean \x00gcdata, as it may be out of date */
+ if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) {
+ gcdata_arr = *gcdata_arr_pp;
+ zend_hash_clean(Z_ARRVAL_P(gcdata_arr));
+ }
+
+ if (gcdata_arr == NULL) {
+ MAKE_STD_ZVAL(gcdata_arr);
+ array_init(gcdata_arr);
+ /* don't decrease refcount of members when destroying */
+ Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
+
+ /* name starts with \x00 to make tampering in user-land more difficult */
+ zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL);
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
+ add_next_index_zval(gcdata_arr, element->obj);
+ add_next_index_zval(gcdata_arr, element->inf);
+ zend_hash_move_forward_ex(&intern->storage, &pos);
+ }
+
+ return props;
+}
+/* }}} */
+
+static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */
+{
+ zval result;
+
+ if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) {
+ return 1;
+ }
+
+ return Z_LVAL(result);
+}
+/* }}} */
+
+static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
+{
+ zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC);
+ zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC);
+
+ if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
+ return 1;
+ }
+
+ return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_array_object_new */
+static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ spl_SplObjectStorage *tmp;
+ return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
+}
+/* }}} */
+
+int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */
+{
+ int hash_len, found;
+ char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+ if (!hash) {
+ return 0;
+ }
+
+ found = zend_hash_exists(&intern->storage, hash, hash_len);
+ spl_object_storage_free_hash(intern, hash);
+ return found;
+} /* }}} */
+
+/* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL)
+ Attaches an object to the storage if not yet contained */
+SPL_METHOD(SplObjectStorage, attach)
+{
+ zval *obj, *inf = NULL;
+
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
+ return;
+ }
+ spl_object_storage_attach(intern, getThis(), obj, inf TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void SplObjectStorage::detach($obj)
+ Detaches an object from the storage */
+SPL_METHOD(SplObjectStorage, detach)
+{
+ zval *obj;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+ spl_object_storage_detach(intern, getThis(), obj TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ intern->index = 0;
+} /* }}} */
+
+/* {{{ proto string SplObjectStorage::getHash($object)
+ Returns the hash of an object */
+SPL_METHOD(SplObjectStorage, getHash)
+{
+ zval *obj;
+ char *hash;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+
+ hash = emalloc(33);
+ php_spl_object_hash(obj, hash TSRMLS_CC);
+
+ RETVAL_STRING(hash, 0);
+
+} /* }}} */
+
+/* {{{ proto mixed SplObjectStorage::offsetGet($object)
+ Returns associated information for a stored object */
+SPL_METHOD(SplObjectStorage, offsetGet)
+{
+ zval *obj;
+ spl_SplObjectStorageElement *element;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *hash;
+ int hash_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+
+ hash = spl_object_storage_get_hash(intern, getThis(), obj, &hash_len TSRMLS_CC);
+ if (!hash) {
+ return;
+ }
+
+ element = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+ spl_object_storage_free_hash(intern, hash);
+
+ if (!element) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
+ } else {
+ RETURN_ZVAL(element->inf,1, 0);
+ }
+} /* }}} */
+
+/* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os)
+ Add all elements contained in $os */
+SPL_METHOD(SplObjectStorage, addAll)
+{
+ zval *obj;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_SplObjectStorage *other;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
+ return;
+ }
+
+ other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
+
+ spl_object_storage_addall(intern, getThis(), other TSRMLS_CC);
+
+ RETURN_LONG(zend_hash_num_elements(&intern->storage));
+} /* }}} */
+
+/* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os)
+ Remove all elements contained in $os */
+SPL_METHOD(SplObjectStorage, removeAll)
+{
+ zval *obj;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_SplObjectStorage *other;
+ spl_SplObjectStorageElement *element;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
+ return;
+ }
+
+ other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset(&other->storage);
+ while (zend_hash_get_current_data(&other->storage, (void **)&element) == SUCCESS) {
+ if (spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC) == FAILURE) {
+ zend_hash_move_forward(&other->storage);
+ }
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ intern->index = 0;
+
+ RETURN_LONG(zend_hash_num_elements(&intern->storage));
+} /* }}} */
+
+/* {{{ proto bool SplObjectStorage::removeAllExcept(SplObjectStorage $os)
+ Remove elements not common to both this SplObjectStorage instance and $os */
+SPL_METHOD(SplObjectStorage, removeAllExcept)
+{
+ zval *obj;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ spl_SplObjectStorage *other;
+ spl_SplObjectStorageElement *element;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
+ return;
+ }
+
+ other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset(&intern->storage);
+ while (zend_hash_get_current_data(&intern->storage, (void **)&element) == SUCCESS) {
+ if (!spl_object_storage_contains(other, getThis(), element->obj TSRMLS_CC)) {
+ spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC);
+ }
+ zend_hash_move_forward(&intern->storage);
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ intern->index = 0;
+
+ RETURN_LONG(zend_hash_num_elements(&intern->storage));
+}
+/* }}} */
+
+/* {{{ proto bool SplObjectStorage::contains($obj)
+ Determine whethe an object is contained in the storage */
+SPL_METHOD(SplObjectStorage, contains)
+{
+ zval *obj;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+ RETURN_BOOL(spl_object_storage_contains(intern, getThis(), obj TSRMLS_CC));
+} /* }}} */
+
+/* {{{ proto int SplObjectStorage::count()
+ Determine number of objects in storage */
+SPL_METHOD(SplObjectStorage, count)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(zend_hash_num_elements(&intern->storage));
+} /* }}} */
+
+/* {{{ proto void SplObjectStorage::rewind()
+ Rewind to first position */
+SPL_METHOD(SplObjectStorage, rewind)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ intern->index = 0;
+} /* }}} */
+
+/* {{{ proto bool SplObjectStorage::valid()
+ Returns whether current position is valid */
+SPL_METHOD(SplObjectStorage, valid)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
+} /* }}} */
+
+/* {{{ proto mixed SplObjectStorage::key()
+ Returns current key */
+SPL_METHOD(SplObjectStorage, key)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(intern->index);
+} /* }}} */
+
+/* {{{ proto mixed SplObjectStorage::current()
+ Returns current element */
+SPL_METHOD(SplObjectStorage, current)
+{
+ spl_SplObjectStorageElement *element;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
+ return;
+ }
+ RETVAL_ZVAL(element->obj, 1, 0);
+} /* }}} */
+
+/* {{{ proto mixed SplObjectStorage::getInfo()
+ Returns associated information to current element */
+SPL_METHOD(SplObjectStorage, getInfo)
+{
+ spl_SplObjectStorageElement *element;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
+ return;
+ }
+ RETVAL_ZVAL(element->inf, 1, 0);
+} /* }}} */
+
+/* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf)
+ Sets associated information of current element to $inf */
+SPL_METHOD(SplObjectStorage, setInfo)
+{
+ spl_SplObjectStorageElement *element;
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *inf;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
+ return;
+ }
+ zval_ptr_dtor(&element->inf);
+ element->inf = inf;
+ Z_ADDREF_P(inf);
+} /* }}} */
+
+/* {{{ proto void SplObjectStorage::next()
+ Moves position forward */
+SPL_METHOD(SplObjectStorage, next)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ intern->index++;
+} /* }}} */
+
+/* {{{ proto string SplObjectStorage::serialize()
+ Serializes storage */
+SPL_METHOD(SplObjectStorage, serialize)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_SplObjectStorageElement *element;
+ zval members, *pmembers, *flags;
+ HashPosition pos;
+ php_serialize_data_t var_hash;
+ smart_str buf = {0};
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+
+ /* storage */
+ smart_str_appendl(&buf, "x:", 2);
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, zend_hash_num_elements(&intern->storage));
+ php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
+ zval_ptr_dtor(&flags);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
+
+ while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
+ if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) {
+ smart_str_free(&buf);
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+ RETURN_NULL();
+ }
+ php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC);
+ smart_str_appendc(&buf, ',');
+ php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC);
+ smart_str_appendc(&buf, ';');
+ zend_hash_move_forward_ex(&intern->storage, &pos);
+ }
+
+ /* members */
+ smart_str_appendl(&buf, "m:", 2);
+ INIT_PZVAL(&members);
+ Z_ARRVAL(members) = zend_std_get_properties(getThis() TSRMLS_CC);
+ Z_TYPE(members) = IS_ARRAY;
+ pmembers = &members;
+ php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
+
+ /* done */
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ if (buf.c) {
+ RETURN_STRINGL(buf.c, buf.len, 0);
+ } else {
+ RETURN_NULL();
+ }
+
+} /* }}} */
+
+/* {{{ proto void SplObjectStorage::unserialize(string serialized)
+ Unserializes storage */
+SPL_METHOD(SplObjectStorage, unserialize)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ char *buf;
+ int buf_len;
+ const unsigned char *p, *s;
+ php_unserialize_data_t var_hash;
+ zval *pentry, *pmembers, *pcount = NULL, *pinf;
+ long count;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+ return;
+ }
+
+ if (buf_len == 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
+ return;
+ }
+
+ /* storage */
+ s = p = (const unsigned char*)buf;
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+
+ if (*p!= 'x' || *++p != ':') {
+ goto outexcept;
+ }
+ ++p;
+
+ ALLOC_INIT_ZVAL(pcount);
+ if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
+ goto outexcept;
+ }
+
+ --p; /* for ';' */
+ count = Z_LVAL_P(pcount);
+
+ while(count-- > 0) {
+ spl_SplObjectStorageElement *pelement;
+ char *hash;
+ int hash_len;
+
+ if (*p != ';') {
+ goto outexcept;
+ }
+ ++p;
+ if(*p != 'O' && *p != 'C' && *p != 'r') {
+ goto outexcept;
+ }
+ ALLOC_INIT_ZVAL(pentry);
+ if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&pentry);
+ goto outexcept;
+ }
+ if(Z_TYPE_P(pentry) != IS_OBJECT) {
+ zval_ptr_dtor(&pentry);
+ goto outexcept;
+ }
+ ALLOC_INIT_ZVAL(pinf);
+ if (*p == ',') { /* new version has inf */
+ ++p;
+ if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&pinf);
+ goto outexcept;
+ }
+ }
+
+ hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC);
+ if (!hash) {
+ zval_ptr_dtor(&pentry);
+ zval_ptr_dtor(&pinf);
+ goto outexcept;
+ }
+ pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+ spl_object_storage_free_hash(intern, hash);
+ if(pelement) {
+ if(pelement->inf) {
+ var_push_dtor(&var_hash, &pelement->inf);
+ }
+ if(pelement->obj) {
+ var_push_dtor(&var_hash, &pelement->obj);
+ }
+ }
+ spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC);
+ zval_ptr_dtor(&pentry);
+ zval_ptr_dtor(&pinf);
+ }
+
+ if (*p != ';') {
+ goto outexcept;
+ }
+ ++p;
+
+ /* members */
+ if (*p!= 'm' || *++p != ':') {
+ goto outexcept;
+ }
+ ++p;
+
+ ALLOC_INIT_ZVAL(pmembers);
+ if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+ zval_ptr_dtor(&pmembers);
+ goto outexcept;
+ }
+
+ /* copy members */
+ if (!intern->std.properties) {
+ rebuild_object_properties(&intern->std);
+ }
+ zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
+ zval_ptr_dtor(&pmembers);
+
+ /* done reading $serialized */
+ if (pcount) {
+ zval_ptr_dtor(&pcount);
+ }
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ return;
+
+outexcept:
+ if (pcount) {
+ zval_ptr_dtor(&pcount);
+ }
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ return;
+
+} /* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
+ ZEND_ARG_INFO(0, object)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1)
+ ZEND_ARG_INFO(0, object)
+ ZEND_ARG_INFO(0, inf)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
+ ZEND_ARG_INFO(0, serialized)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
+ ZEND_ARG_INFO(0, info)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(arginfo_getHash, 0)
+ ZEND_ARG_INFO(0, object)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
+ ZEND_ARG_INFO(0, object)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_funcs_SplObjectStorage[] = {
+ SPL_ME(SplObjectStorage, attach, arginfo_attach, 0)
+ SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
+ SPL_ME(SplObjectStorage, contains, arginfo_Object, 0)
+ SPL_ME(SplObjectStorage, addAll, arginfo_Object, 0)
+ SPL_ME(SplObjectStorage, removeAll, arginfo_Object, 0)
+ SPL_ME(SplObjectStorage, removeAllExcept, arginfo_Object, 0)
+ SPL_ME(SplObjectStorage, getInfo, arginfo_splobject_void,0)
+ SPL_ME(SplObjectStorage, setInfo, arginfo_setInfo, 0)
+ SPL_ME(SplObjectStorage, getHash, arginfo_getHash, 0)
+ /* Countable */
+ SPL_ME(SplObjectStorage, count, arginfo_splobject_void,0)
+ /* Iterator */
+ SPL_ME(SplObjectStorage, rewind, arginfo_splobject_void,0)
+ SPL_ME(SplObjectStorage, valid, arginfo_splobject_void,0)
+ SPL_ME(SplObjectStorage, key, arginfo_splobject_void,0)
+ SPL_ME(SplObjectStorage, current, arginfo_splobject_void,0)
+ SPL_ME(SplObjectStorage, next, arginfo_splobject_void,0)
+ /* Serializable */
+ SPL_ME(SplObjectStorage, unserialize, arginfo_Serialized, 0)
+ SPL_ME(SplObjectStorage, serialize, arginfo_splobject_void,0)
+ /* ArrayAccess */
+ SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0)
+ SPL_MA(SplObjectStorage, offsetSet, SplObjectStorage, attach, arginfo_attach, 0)
+ SPL_MA(SplObjectStorage, offsetUnset, SplObjectStorage, detach, arginfo_offsetGet, 0)
+ SPL_ME(SplObjectStorage, offsetGet, arginfo_offsetGet, 0)
+ {NULL, NULL, NULL}
+};
+
+typedef enum {
+ MIT_NEED_ANY = 0,
+ MIT_NEED_ALL = 1,
+ MIT_KEYS_NUMERIC = 0,
+ MIT_KEYS_ASSOC = 2
+} MultipleIteratorFlags;
+
+#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1
+#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2
+
+/* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC])
+ Iterator that iterates over several iterators one after the other */
+SPL_METHOD(MultipleIterator, __construct)
+{
+ spl_SplObjectStorage *intern;
+ long flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
+ zend_error_handling error_handling;
+
+ zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+ return;
+ }
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ intern->flags = flags;
+ zend_restore_error_handling(&error_handling TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int MultipleIterator::getFlags()
+ Return current flags */
+SPL_METHOD(MultipleIterator, getFlags)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ RETURN_LONG(intern->flags);
+}
+/* }}} */
+
+/* {{{ proto int MultipleIterator::setFlags(int flags)
+ Set flags */
+SPL_METHOD(MultipleIterator, setFlags)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException
+ Attach a new iterator */
+SPL_METHOD(MultipleIterator, attachIterator)
+{
+ spl_SplObjectStorage *intern;
+ zval *iterator = NULL, *info = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (info != NULL) {
+ spl_SplObjectStorageElement *element;
+ zval compare_result;
+
+ if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
+ is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
+ if (Z_LVAL(compare_result)) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
+ return;
+ }
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+ }
+
+ spl_object_storage_attach(intern, getThis(), iterator, info TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void MultipleIterator::rewind()
+ Rewind all attached iterator instances */
+SPL_METHOD(MultipleIterator, rewind)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto void MultipleIterator::next()
+ Move all attached iterator instances forward */
+SPL_METHOD(MultipleIterator, next)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool MultipleIterator::valid()
+ Return whether all or one sub iterator is valid depending on flags */
+SPL_METHOD(MultipleIterator, valid)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it, *retval = NULL;
+ long expect, valid;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!zend_hash_num_elements(&intern->storage)) {
+ RETURN_FALSE;
+ }
+
+ expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+
+ if (retval) {
+ valid = Z_LVAL_P(retval);
+ zval_ptr_dtor(&retval);
+ } else {
+ valid = 0;
+ }
+
+ if (expect != valid) {
+ RETURN_BOOL(!expect);
+ }
+
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+
+ RETURN_BOOL(expect);
+}
+/* }}} */
+
+static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorageElement *element;
+ zval *it, *retval = NULL;
+ int valid = 1, num_elements;
+
+ num_elements = zend_hash_num_elements(&intern->storage);
+ if (num_elements < 1) {
+ RETURN_FALSE;
+ }
+
+ array_init_size(return_value, num_elements);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+
+ if (retval) {
+ valid = Z_LVAL_P(retval);
+ zval_ptr_dtor(&retval);
+ } else {
+ valid = 0;
+ }
+
+ if (valid) {
+ if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
+ } else {
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval);
+ }
+ if (!retval) {
+ zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
+ return;
+ }
+ } else if (intern->flags & MIT_NEED_ALL) {
+ if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
+ zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
+ }
+ return;
+ } else {
+ ALLOC_INIT_ZVAL(retval);
+ }
+
+ if (intern->flags & MIT_KEYS_ASSOC) {
+ switch (Z_TYPE_P(element->inf)) {
+ case IS_LONG:
+ add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
+ break;
+ case IS_STRING:
+ add_assoc_zval_ex(return_value, Z_STRVAL_P(element->inf), Z_STRLEN_P(element->inf)+1U, retval);
+ break;
+ default:
+ zval_ptr_dtor(&retval);
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
+ return;
+ }
+ } else {
+ add_next_index_zval(return_value, retval);
+ }
+
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto array current() throws RuntimeException throws InvalidArgumentException
+ Return an array of all registered Iterator instances current() result */
+SPL_METHOD(MultipleIterator, current)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto array MultipleIterator::key()
+ Return an array of all registered Iterator instances key() result */
+SPL_METHOD(MultipleIterator, key)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, infos)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_MultipleIterator[] = {
+ SPL_ME(MultipleIterator, __construct, arginfo_MultipleIterator_setflags, 0)
+ SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0)
+ SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0)
+ SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0)
+ SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0)
+ SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
+ SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0)
+ /* Iterator */
+ SPL_ME(MultipleIterator, rewind, arginfo_splobject_void, 0)
+ SPL_ME(MultipleIterator, valid, arginfo_splobject_void, 0)
+ SPL_ME(MultipleIterator, key, arginfo_splobject_void, 0)
+ SPL_ME(MultipleIterator, current, arginfo_splobject_void, 0)
+ SPL_ME(MultipleIterator, next, arginfo_splobject_void, 0)
+ {NULL, NULL, NULL}
+};
+
+/* {{{ PHP_MINIT_FUNCTION(spl_observer) */
+PHP_MINIT_FUNCTION(spl_observer)
+{
+ REGISTER_SPL_INTERFACE(SplObserver);
+ REGISTER_SPL_INTERFACE(SplSubject);
+
+ REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
+ memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+
+ spl_handler_SplObjectStorage.get_debug_info = spl_object_storage_debug_info;
+ spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects;
+ spl_handler_SplObjectStorage.clone_obj = spl_object_storage_clone;
+ spl_handler_SplObjectStorage.get_gc = spl_object_storage_get_gc;
+
+ REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
+ REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
+ REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
+ REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
+
+ REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
+ REGISTER_SPL_ITERATOR(MultipleIterator);
+
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY", MIT_NEED_ANY);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL", MIT_NEED_ALL);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC", MIT_KEYS_ASSOC);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_observer.h b/ext/spl/spl_observer.h
new file mode 100644
index 0000000..e93e304
--- /dev/null
+++ b/ext/spl/spl_observer.h
@@ -0,0 +1,43 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef SPL_OBSERVER_H
+#define SPL_OBSERVER_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_SplObserver;
+extern PHPAPI zend_class_entry *spl_ce_SplSubject;
+extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
+extern PHPAPI zend_class_entry *spl_ce_MultipleIterator;
+
+PHP_MINIT_FUNCTION(spl_observer);
+
+#endif /* SPL_OBSERVER_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt b/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt
new file mode 100644
index 0000000..75d8a41
--- /dev/null
+++ b/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt
@@ -0,0 +1,16 @@
+--TEST--
+ArrayObject: test that you cannot unserialize a empty string
+--CREDITS--
+Havard Eide <nucleuz@gmail.com>
+#PHPTestFest2009 Norway 2009-06-09 \o/
+--FILE--
+<?php
+$a = new ArrayObject(array());
+$a->unserialize("");
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Empty serialized string cannot be empty' in %s.php:%d
+Stack trace:
+#0 %s(%d): ArrayObject->unserialize('')
+#1 {main}
+ thrown in %s.php on line %d
diff --git a/ext/spl/tests/CallbackFilterIteratorTest-002.phpt b/ext/spl/tests/CallbackFilterIteratorTest-002.phpt
new file mode 100644
index 0000000..cbad2e3
--- /dev/null
+++ b/ext/spl/tests/CallbackFilterIteratorTest-002.phpt
@@ -0,0 +1,50 @@
+--TEST--
+CallbackFilterIterator 002
+--FILE--
+<?php
+
+set_error_handler(function($errno, $errstr){
+ echo $errstr . "\n";
+ return true;
+});
+
+try {
+ new CallbackFilterIterator();
+} catch(InvalidArgumentException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ new CallbackFilterIterator(null);
+} catch(InvalidArgumentException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ new CallbackFilterIterator(new ArrayIterator(array()), null);
+} catch(InvalidArgumentException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ new CallbackFilterIterator(new ArrayIterator(array()), array());
+} catch(InvalidArgumentException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+$it = new CallbackFilterIterator(new ArrayIterator(array(1)), function() {
+ throw new Exception("some message");
+});
+try {
+ foreach($it as $e);
+} catch(Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+--EXPECT--
+CallbackFilterIterator::__construct() expects exactly 2 parameters, 0 given
+Argument 1 passed to CallbackFilterIterator::__construct() must implement interface Iterator, null given
+CallbackFilterIterator::__construct() expects exactly 2 parameters, 1 given
+CallbackFilterIterator::__construct() expects parameter 2 to be a valid callback, no array or string given
+CallbackFilterIterator::__construct() expects parameter 2 to be a valid callback, array must have exactly two members
+some message
diff --git a/ext/spl/tests/CallbackFilterIteratorTest.phpt b/ext/spl/tests/CallbackFilterIteratorTest.phpt
new file mode 100644
index 0000000..36bc770
--- /dev/null
+++ b/ext/spl/tests/CallbackFilterIteratorTest.phpt
@@ -0,0 +1,133 @@
+--TEST--
+CallbackFilterIterator
+--FILE--
+<?php
+
+class A {
+ function test($value, $key, $inner) {
+ return test($value, $key, $inner);
+ }
+}
+
+class B {
+ static function test($value, $key, $inner) {
+ return test($value, $key, $inner);
+ }
+}
+
+function test($value, $key, $inner) {
+ printf("%s / %s / %d / %d\n"
+ , $value
+ , $key
+ , $value == $inner->current()
+ , $key == $inner->key()
+ );
+ return $value === 1 || $value === 4;
+}
+
+$tests = array(
+ 'instance method' => function() { return array(new A, 'test'); },
+ 'static method' => function() { return array('B', 'test'); },
+ 'static method (2)' => function() { return 'B::test'; },
+ 'function' => function() { return 'test'; },
+ 'anonymous function' => function() { return function($value, $key, $inner) { return test($value, $key, $inner); }; },
+);
+
+foreach($tests as $name => $test) {
+
+ $callback = $test();
+ $it = new ArrayIterator(range(1, 5));
+ $it = new CallbackFilterIterator($it, $callback);
+
+ echo " = $name =\n";
+
+ foreach($it as $value) {
+ echo "=> $value\n";
+ }
+
+ // same test, with no reference to callback
+
+ $it = new ArrayIterator(range(1, 5));
+ $it = new CallbackFilterIterator($it, $test());
+ unset($callback);
+
+ foreach($it as $value) {
+ echo "=> $value\n";
+ }
+}
+--EXPECT--
+= instance method =
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+ = static method =
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+ = static method (2) =
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+ = function =
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+ = anonymous function =
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 1 / 1 / 1
+3 / 2 / 1 / 1
+4 / 3 / 1 / 1
+=> 4
+5 / 4 / 1 / 1
diff --git a/ext/spl/tests/DirectoryIterator_by_reference.phpt b/ext/spl/tests/DirectoryIterator_by_reference.phpt
new file mode 100644
index 0000000..06127ec
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_by_reference.phpt
@@ -0,0 +1,14 @@
+--TEST--
+DirectoryIterator: test that you cannot use iterator with reference
+--CREDITS--
+Havard Eide <nucleuz@gmail.com>
+#PHPTestFest2009 Norway 2009-06-09 \o/
+--FILE--
+<?php
+$it = new DirectoryIterator(__DIR__);
+foreach( $it as &$file ) {
+ echo $file . "\n";
+}
+?>
+--EXPECTF--
+Fatal error: An iterator cannot be used with foreach by reference in %s on line %d
diff --git a/ext/spl/tests/DirectoryIterator_empty_constructor.phpt b/ext/spl/tests/DirectoryIterator_empty_constructor.phpt
new file mode 100644
index 0000000..da5276c
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_empty_constructor.phpt
@@ -0,0 +1,15 @@
+--TEST--
+DirectoryIterator: Test empty value to DirectoryIterator constructor
+--CREDITS--
+Havard Eide <nucleuz@gmail.com>
+#PHPTestFest2009 Norway 2009-06-09 \o/
+--FILE--
+<?php
+$it = new DirectoryIterator("");
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'Directory name must not be empty.' in %s:%d
+Stack trace:
+#0 %s(%d): DirectoryIterator->__construct('')
+#1 {main}
+ thrown in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt b/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt
new file mode 100644
index 0000000..ed1f473
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt
@@ -0,0 +1,23 @@
+--TEST--
+DirectoryIterator::getBasename() - Basic Test
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+ $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename');
+ mkdir($targetDir);
+ touch($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt');
+ $dir = new DirectoryIterator($targetDir.DIRECTORY_SEPARATOR);
+ while(!$dir->isFile()) {
+ $dir->next();
+ }
+ echo $dir->getBasename('.txt');
+?>
+--CLEAN--
+<?php
+ $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename');
+ unlink($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt');
+ rmdir($targetDir);
+?>
+--EXPECTF--
+getBasename_test
diff --git a/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt b/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt
new file mode 100644
index 0000000..b2df8a5
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt
@@ -0,0 +1,23 @@
+--TEST--
+DirectoryIterator::getBasename() - Pass unexpected array
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+ $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename');
+ mkdir($targetDir);
+ touch($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt');
+ $dir = new DirectoryIterator($targetDir.DIRECTORY_SEPARATOR);
+ while(!$dir->isFile()) {
+ $dir->next();
+ }
+ echo $dir->getBasename(array());
+?>
+--CLEAN--
+<?php
+ $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename');
+ unlink($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt');
+ rmdir($targetDir);
+?>
+--EXPECTF--
+Warning: DirectoryIterator::getBasename() expects parameter 1 to be %binary_string_optional%, array given in %s on line %d
diff --git a/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt b/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt
new file mode 100644
index 0000000..7398d4b
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt
@@ -0,0 +1,57 @@
+--TEST--
+SPL: DirectoryIterator::getExtension() basic test
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ die('skip.. only for Unix');
+}
+?>
+--FILE--
+<?php
+$dir = __DIR__ . DIRECTORY_SEPARATOR . md5('DirectoryIterator::getExtension') . DIRECTORY_SEPARATOR;
+mkdir($dir);
+
+$files = array('test.txt', 'test.extension', 'test..', 'test.', 'test');
+foreach ($files as $file) {
+ touch($dir . $file);
+}
+
+$dit_exts = array();
+$nfo_exts = array();
+$skip = array('.', '..');
+
+foreach (new DirectoryIterator($dir) as $file) {
+ if (in_array($file->getFilename(), $skip)) {
+ continue;
+ }
+ $dit_exts[] = $file->getExtension();
+ $nfo_exts[] = pathinfo($file->getFilename(), PATHINFO_EXTENSION);
+}
+var_dump($dit_exts === $nfo_exts);
+sort($dit_exts);
+var_dump($dit_exts);
+?>
+--CLEAN--
+<?php
+$dir = __DIR__ . DIRECTORY_SEPARATOR . md5('DirectoryIterator::getExtension') . DIRECTORY_SEPARATOR;
+$files = array('test.txt', 'test.extension', 'test..', 'test.', 'test');
+foreach ($files as $file) {
+ unlink($dir . $file);
+}
+rmdir($dir);
+?>
+--EXPECTF--
+bool(true)
+array(5) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+ [2]=>
+ string(0) ""
+ [3]=>
+ string(9) "extension"
+ [4]=>
+ string(3) "txt"
+}
+
diff --git a/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt b/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt
new file mode 100644
index 0000000..0c75bf4
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: DirectoryIterator test getGroup
+--SKIPIF--
+<?php
+if (posix_geteuid() == 0) die('SKIP Cannot run test as root.');
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--FILE--
+<?php
+$dirname = 'DirectoryIterator_getGroup_basic';
+mkdir($dirname);
+$dir = new DirectoryIterator($dirname);
+$expected = filegroup($dirname);
+$actual = $dir->getGroup();
+var_dump($expected == $actual);
+?>
+--CLEAN--
+<?php
+$dirname = 'DirectoryIterator_getGroup_basic';
+rmdir($dirname);
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/DirectoryIterator_getInode_basic.phpt b/ext/spl/tests/DirectoryIterator_getInode_basic.phpt
new file mode 100644
index 0000000..4fd7e8d
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getInode_basic.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: Spl Directory Iterator test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+mkdir('test_dir_ptfi');
+$dirIterator = new DirectoryIterator('test_dir_ptfi');
+var_dump(decoct($dirIterator->getInode()));
+
+?>
+--CLEAN--
+<?php
+rmdir('test_dir_ptfi');
+?>
+--EXPECTF--
+string(%d) "%d"
diff --git a/ext/spl/tests/DirectoryIterator_getInode_error.phpt b/ext/spl/tests/DirectoryIterator_getInode_error.phpt
new file mode 100644
index 0000000..c3641f9
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getInode_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Spl File Info test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+$fileInfo = new SplFileInfo('not_existing');
+var_dump($fileInfo->getInode());
+?>
+
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getInode(): stat failed for %s' in %s
+Stack trace:
+#0 %s: SplFileInfo->getInode()
+#1 {main}
+ thrown in %s
diff --git a/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt b/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt
new file mode 100644
index 0000000..a1092c2
--- /dev/null
+++ b/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: DirectoryIterator test getOwner
+--SKIPIF--
+<?php
+if (posix_geteuid() == 0) die('SKIP Cannot run test as root.');
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--FILE--
+<?php
+$dirname = 'DirectoryIterator_getOwner_basic';
+mkdir($dirname);
+$dir = new DirectoryIterator($dirname);
+$expected = fileowner($dirname);
+$actual = $dir->getOwner();
+var_dump($expected == $actual);
+?>
+--CLEAN--
+<?php
+$dirname = 'DirectoryIterator_getOwner_basic';
+rmdir($dirname);
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt b/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt
new file mode 100644
index 0000000..f55afd8
--- /dev/null
+++ b/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt
@@ -0,0 +1,138 @@
+--TEST--
+RecursiveCallbackFilterIterator
+--FILE--
+<?php
+
+class A {
+ function test($value, $key, $inner) {
+ return test($value, $key, $inner);
+ }
+}
+
+class B {
+ static function test($value, $key, $inner) {
+ return test($value, $key, $inner);
+ }
+}
+
+function test($value, $key, $inner) {
+ if ($inner->hasChildren()) {
+ return true;
+ }
+ printf("%s / %s / %d / %d\n"
+ , print_r($value, true)
+ , $key
+ , $value == $inner->current()
+ , $key == $inner->key()
+ );
+ return $value === 1 || $value === 4;
+}
+
+$tests = array(
+ 'instance method' => function() { return array(new A, 'test'); },
+ 'static method' => function() { return array('B', 'test'); },
+ 'static method (2)' => function() { return 'B::test'; },
+ 'function' => function() { return 'test'; },
+ 'anonymous function' => function() { return function($value, $key, $inner) { return test($value, $key, $inner); }; },
+);
+
+foreach($tests as $name => $test) {
+
+ $callback = $test();
+ $it = new RecursiveArrayIterator(array(1, array(2, 3), array(4, 5)));
+ $it = new RecursiveCallbackFilterIterator($it, $callback);
+ $it = new RecursiveIteratorIterator($it);
+
+ echo " = $name =\n";
+
+ foreach($it as $value) {
+ echo "=> $value\n";
+ }
+
+ // same test, with no reference to callback
+
+ $it = new RecursiveArrayIterator(array(1, array(2, 3), array(4, 5)));
+ $it = new RecursiveCallbackFilterIterator($it, $test());
+ $it = new RecursiveIteratorIterator($it);
+ unset($callback);
+
+ foreach($it as $value) {
+ echo "=> $value\n";
+ }
+}
+--EXPECT--
+= instance method =
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+ = static method =
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+ = static method (2) =
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+ = function =
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+ = anonymous function =
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
+1 / 0 / 1 / 1
+=> 1
+2 / 0 / 1 / 1
+3 / 1 / 1 / 1
+4 / 0 / 1 / 1
+=> 4
+5 / 1 / 1 / 1
diff --git a/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt b/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt
new file mode 100644
index 0000000..f0b2b01
--- /dev/null
+++ b/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt
@@ -0,0 +1,50 @@
+--TEST--
+RecursiveDirectoryIterator::getBasePath() - basic test
+--CREDITS--
+Pawel Krynicki <pawel [dot] krynicki [at] xsolve [dot] pl>
+#testfest AmsterdamPHP 2012-06-23
+--FILE--
+<?php
+$depth0 = "depth0";
+$depth1 = 'depth1';
+$depth2 = 'depth2';
+$targetDir = __DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . $depth2;
+mkdir($targetDir, 0777, true);
+touch($targetDir . DIRECTORY_SEPARATOR . 'getSubPath_test.tmp');
+$iterator = new RecursiveDirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . $depth0);
+$it = new RecursiveIteratorIterator($iterator);
+
+$list = [];
+while($it->valid()) {
+ $list[] = $it->getSubPath();
+ $it->next();
+}
+asort($list);
+foreach ($list as $item) {
+ echo $item . "\n";
+}
+?>
+--CLEAN--
+<?php
+function rrmdir($dir) {
+ foreach(glob($dir . '/*') as $file) {
+ if(is_dir($file)) {
+ rrmdir($file);
+ } else {
+ unlink($file);
+ }
+ }
+
+ rmdir($dir);
+}
+
+$targetDir = __DIR__.DIRECTORY_SEPARATOR . "depth0";
+rrmdir($targetDir);
+?>
+
+--EXPECTF--
+depth1
+depth1
+depth1%cdepth2
+depth1%cdepth2
+depth1%cdepth2
diff --git a/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt b/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt
new file mode 100644
index 0000000..7b12672
--- /dev/null
+++ b/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt
@@ -0,0 +1,56 @@
+--TEST--
+RecursiveDirectoryIterator::getBasePathname() - basic test
+--CREDITS--
+Pawel Krynicki <pawel [dot] krynicki [at] xsolve [dot] pl>
+#testfest AmsterdamPHP 2012-06-23
+--FILE--
+<?php
+$depth0 = "depth0";
+$depth1 = "depth1";
+$depth2 = "depth2";
+$targetDir = __DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . $depth2;
+mkdir($targetDir, 0777, true);
+touch($targetDir . DIRECTORY_SEPARATOR . 'getSubPathname_test_2.tmp');
+touch(__DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . 'getSubPathname_test_3.tmp');
+touch(__DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . 'getSubPathname_test_1.tmp');
+$iterator = new RecursiveDirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . $depth0);
+$it = new RecursiveIteratorIterator($iterator);
+
+$list = [];
+$it->rewind(); //see https://bugs.php.net/bug.php?id=62914
+while($it->valid()) {
+ $list[] = $it->getSubPathname();
+ $it->next();
+}
+asort($list);
+foreach ($list as $item) {
+ echo $item . "\n";
+}
+?>
+--CLEAN--
+<?php
+function rrmdir($dir) {
+ foreach(glob($dir . '/*') as $file) {
+ if(is_dir($file)) {
+ rrmdir($file);
+ } else {
+ unlink($file);
+ }
+ }
+
+ rmdir($dir);
+}
+
+$targetDir = __DIR__ . DIRECTORY_SEPARATOR . "depth0";
+rrmdir($targetDir);
+?>
+--EXPECTF--
+.
+..
+depth1%c.
+depth1%c..
+depth1%cdepth2%c.
+depth1%cdepth2%c..
+depth1%cdepth2%cgetSubPathname_test_2.tmp
+depth1%cgetSubPathname_test_3.tmp
+getSubPathname_test_1.tmp
diff --git a/ext/spl/tests/SplArray_fromArray.phpt b/ext/spl/tests/SplArray_fromArray.phpt
new file mode 100644
index 0000000..1144f5f
--- /dev/null
+++ b/ext/spl/tests/SplArray_fromArray.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Check that SplArray::fromArray will not allow integer overflows
+--CREDITS--
+Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009
+--FILE--
+<?php
+$array = array(PHP_INT_MAX => 'foo');
+$splArray = new SplFixedArray();
+
+try {
+ $splArray->fromArray($array);
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECT--
+integer overflow detected \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt
new file mode 100644
index 0000000..36b186d
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::bottom() - pass in an unexpected array parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->bottom(array());
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt
new file mode 100644
index 0000000..94312a0
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::bottom() - pass in an unexpected float parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->bottom(3.14159);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt
new file mode 100644
index 0000000..651f1e4
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::bottom() - pass in an unexpected integer parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->bottom(45);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt
new file mode 100644
index 0000000..efc6b8a
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::bottom() - pass in an unexpected null parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->bottom(null);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_count.phpt b/ext/spl/tests/SplDoublyLinkedList_count.phpt
new file mode 100644
index 0000000..72b029c
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_count.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Check that SplDoublyLinkedList::count fails if parameter passed in
+--CREDITS--
+Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+
+$c = $list->count('foo');
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::count() expects exactly 0 parameters, 1 given in %s on line 4
diff --git a/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt b/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt
new file mode 100644
index 0000000..36c72de
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Create a SplDoublyLinkedList, call count() and pass a SplDoublyLinkedList object as the parameter.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList(2);
+$dll->count(new SplDoublyLinkedList(2));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::count() expects exactly 0 parameters, 1 given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_current.phpt b/ext/spl/tests/SplDoublyLinkedList_current.phpt
new file mode 100644
index 0000000..3e13a6b
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_current.phpt
@@ -0,0 +1,11 @@
+--TEST--
+SplDoublyLinkedList getIteratorMode
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+var_dump($list->current());
+?>
+--EXPECT--
+NULL
diff --git a/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt
new file mode 100644
index 0000000..558504b
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Run current() function on an empty SplDoublyLinkedList.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+var_dump($list->current());
+
+?>
+--EXPECT--
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt b/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt
new file mode 100644
index 0000000..3164b42
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Check that SplDoublyLinkedList returns debug info when print_r is used.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ // Add some items to the list
+ $dll->push(1);
+ $dll->push(2);
+ $dll->push(3);
+
+ // Check the debug info
+ print_r($dll);
+?>
+--EXPECT--
+SplDoublyLinkedList Object
+(
+ [flags:SplDoublyLinkedList:private] => 0
+ [dllist:SplDoublyLinkedList:private] => Array
+ (
+ [0] => 1
+ [1] => 2
+ [2] => 3
+ )
+
+)
diff --git a/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt
new file mode 100644
index 0000000..d1bfb46
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplDoublyLinkedList getIteratorMode
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$list->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP);
+echo $list->getIteratorMode();
+?>
+--EXPECT--
+0
diff --git a/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt
new file mode 100644
index 0000000..cb43bee
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplDoublyLinkedList getIteratorMode with an unexpected parameter
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$list->getIteratorMode(24);
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::getIteratorMode() expects exactly 0 parameters, 1 given in %s on line %d
+
diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt
new file mode 100644
index 0000000..8d7aaf8
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Check that SplDoublyLinkedList->isEmpty() returns an error message when a parameter is passed.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ var_dump($dll->isEmpty("test"));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::isEmpty() expects exactly 0 parameters, %d given in %s
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt
new file mode 100644
index 0000000..f129385
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that SplDoublyLinkedList->isEmpty() correctly returns true for an empty list.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ var_dump($dll->isEmpty());
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt
new file mode 100644
index 0000000..6ea9198
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Check that SplDoublyLinkedList->isEmpty() returns an error message when a parameter is passed.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ // Add some items to the list
+ $dll->push(1);
+ $dll->push(2);
+ $dll->push(3);
+ //var_dump($dll);
+
+ var_dump($dll->isEmpty("test"));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::isEmpty() expects exactly 0 parameters, %d given in %s
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt
new file mode 100644
index 0000000..cac1866
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Check that SplDoublyLinkedList->isEmpty() correctly returns true for a non-empty list.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ // Add some items to the list
+ $dll->push(1);
+ $dll->push(2);
+ $dll->push(3);
+ //var_dump($dll);
+
+ var_dump($dll->isEmpty());
+?>
+--EXPECT--
+bool(false)
diff --git a/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt b/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt
new file mode 100644
index 0000000..86a8456
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Check that SplDoublyLinkedList can traverse backwards
+--CREDITS--
+Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+
+$list->push('o');
+$list->push('o');
+$list->push('f');
+
+$list->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
+
+$list->rewind();
+
+while ($tmp = $list->current()) {
+ echo $tmp;
+ $list->next();
+}
+?>
+--EXPECT--
+foo \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt
new file mode 100644
index 0000000..f0e1b8b
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL SplDoublyLinkedList offsetExists displays warning and returns null on no parameters
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$a = $list->offsetExists();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::offsetExists() expects exactly 1 parameter, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt
new file mode 100644
index 0000000..0399b49
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL SplDoublyLinkedList offsetExists returns correct values
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+
+// Push two values onto the list
+$list->push('abc');
+$list->push('def');
+
+// Validate that we can see the first value
+if($list->offsetExists(0) === true) {
+ echo "PASS\n";
+}
+
+// Validate that we can see the second value
+if($list->offsetExists(1) === true) {
+ echo "PASS\n";
+}
+
+// Check that there is no third value
+if($list->offsetExists(2) === false) {
+ echo "PASS\n";
+}
+?>
+--EXPECTF--
+PASS
+PASS
+PASS
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt
new file mode 100644
index 0000000..36c47fe
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::offsetGet() with no parameter passed.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplDoublyLinkedList( );
+
+$get = $array->offsetGet();
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt
new file mode 100644
index 0000000..beffe7a
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Tests that the offsetGet() method throws an error when no argument is sent
+--CREDITS--
+PHPNW Test Fest 2009 - Rick Ogden
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->push(1);
+$dll->push(2);
+
+var_dump($dll->offsetGet());
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt
new file mode 100644
index 0000000..5df4ab5
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplDoublyLinkedList::offsetGet() with 1st parameter passed as array.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplDoublyLinkedList( );
+
+$get = $array->offsetGet( array( 'fail' ) );
+
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'OutOfRangeException' with message 'Offset invalid or out of range' in %s
+Stack trace:
+#0 %s
+#1 {main}
+ thrown in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt
new file mode 100644
index 0000000..fcff762
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplDoublyLinkedList::offsetGet() with 1st parameter passed as string.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplDoublyLinkedList( );
+
+$get = $array->offsetGet( 'fail' );
+
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'OutOfRangeException' with message 'Offset invalid or out of range' in %s
+Stack trace:
+#0 %s
+#1 {main}
+ thrown in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt
new file mode 100644
index 0000000..2447e79
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SplDoublyLinkedList offsetSet throws error on no parameters
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$a = $list->offsetSet();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::offsetSet() expects exactly 2 parameters, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt
new file mode 100644
index 0000000..244dcd5
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SplDoublyLinkedList offsetSet throws error only one parameter
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$a = $list->offsetSet(2);
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::offsetSet() expects exactly 2 parameters, 1 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt
new file mode 100644
index 0000000..687fcad
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Doubly Linked List - offsetUnset > number elements
+
+--CREDITS--
+PHPNW Test Fest 2009 - Mat Griffin
+
+--FILE--
+<?php
+$ll = new SplDoublyLinkedList();
+
+$ll->push('1');
+$ll->push('2');
+$ll->push('3');
+
+try {
+
+$ll->offsetUnset($ll->count() + 1);
+
+var_dump($ll);
+
+} catch(Exception $e) {
+echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Offset out of range
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt
new file mode 100644
index 0000000..d3d1d7d
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Check that SplDoublyLinkedList->offsetUnset() returns an error message when the offset is < 0.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ // Add some items to the list
+ $dll->push(1);
+ $dll->push(2);
+ $dll->push(3);
+
+ try {
+ $dll->offsetUnset(-1);
+ }
+ catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+?>
+--EXPECT--
+Offset out of range
diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt
new file mode 100644
index 0000000..aea73b9
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Check that SplDoublyLinkedList->offsetUnset() returns an error message when the offset is > elements.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a new Doubly Linked List
+ $dll = new SplDoublyLinkedList();
+
+ // Add some items to the list
+ $dll->push(1);
+ $dll->push(2);
+ $dll->push(3);
+
+ try {
+ $dll->offsetUnset(3);
+ }
+ catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+?>
+--EXPECT--
+Offset out of range
diff --git a/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt b/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt
new file mode 100644
index 0000000..64f3a48
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Checks that the pop() method of DoublyLinkedList does not accept args.
+--CREDITS--
+PHPNW Test Fest 2009 - Rick Ogden
+--FILE--
+<?php
+$ll = new SplDoublyLinkedList();
+$ll->push(1);
+$ll->push(2);
+
+var_dump($ll->pop(1));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::pop() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
diff --git a/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt b/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt
new file mode 100644
index 0000000..11ab343
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::offsetGet() with no parameter passed.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplDoublyLinkedList( );
+
+$get = $array->pop( 'param' );
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::pop() expects exactly 0 parameters, 1 given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt
new file mode 100644
index 0000000..057751c
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that SplDoublyLinkedList::push generate a warning and return NULL with missing param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+var_dump($dll->push());
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::push() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplDoublyLinkedList_serialization.phpt b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt
new file mode 100644
index 0000000..7ab7d78
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt
@@ -0,0 +1,67 @@
+--TEST--
+Check Serialization/unserialization
+--FILE--
+<?php
+$q = new SplQueue();
+
+$q->enqueue("a");
+$q->enqueue("b");
+
+var_dump($q, $ss = serialize($q), unserialize($ss));
+
+$s = new SplStack();
+
+$s->push("a");
+$s->push("b");
+
+var_dump($s, $ss = serialize($s), unserialize($ss));
+?>
+==END==
+--EXPECTF--
+object(SplQueue)#%d (2) {
+ ["flags":"SplDoublyLinkedList":private]=>
+ int(4)
+ ["dllist":"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ string(1) "a"
+ [1]=>
+ string(1) "b"
+ }
+}
+string(42) "C:8:"SplQueue":22:{i:4;:s:1:"a";:s:1:"b";}"
+object(SplQueue)#%d (2) {
+ ["flags":"SplDoublyLinkedList":private]=>
+ int(4)
+ ["dllist":"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ string(1) "a"
+ [1]=>
+ string(1) "b"
+ }
+}
+object(SplStack)#%d (2) {
+ ["flags":"SplDoublyLinkedList":private]=>
+ int(6)
+ ["dllist":"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ string(1) "a"
+ [1]=>
+ string(1) "b"
+ }
+}
+string(42) "C:8:"SplStack":22:{i:6;:s:1:"a";:s:1:"b";}"
+object(SplStack)#%d (2) {
+ ["flags":"SplDoublyLinkedList":private]=>
+ int(6)
+ ["dllist":"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ string(1) "a"
+ [1]=>
+ string(1) "b"
+ }
+}
+==END==
diff --git a/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt b/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt
new file mode 100644
index 0000000..9bf7a32
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Create a SplDoublyLinkedList, call setIteratorMode() and pass a SplDoublyLinkedList object as the parameter.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList(2);
+$dll->setIteratorMode(new SplDoublyLinkedList(2));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::setIteratorMode() expects parameter 1 to be long, object given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt
new file mode 100644
index 0000000..2e2632d
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::top() - pass in an unexpected array
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->top(array());
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt
new file mode 100644
index 0000000..0a481b8
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::top() - pass in an unexpected float parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->top(3.14159);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt
new file mode 100644
index 0000000..72bdbab
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::top() - pass in an unexpected integer parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->top(45);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt
new file mode 100644
index 0000000..6a92399
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplDoublyLinkedList::top() - pass in an unexpected null parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+
+$list = new SplDoublyLinkedList();
+$list->push("top");
+$list->top(null);
+
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt
new file mode 100644
index 0000000..18afa03
--- /dev/null
+++ b/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Check that SplDoublyLinkedList::unshift generate a warning and return NULL with missing param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+var_dump($dll->unshift());
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::unshift() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt
new file mode 100644
index 0000000..4dce4db
--- /dev/null
+++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: SplDoublyLinkedList : offsetUnset - first element
+--CREDITS--
+PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org>
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$list->push('oh');
+$list->push('hai');
+$list->push('thar');
+$list->offsetUnset(0);
+var_dump($list);
+?>
+--EXPECTF--
+object(SplDoublyLinkedList)#1 (2) {
+ [%u|b%"flags":%u|b%"SplDoublyLinkedList":private]=>
+ int(0)
+ [%u|b%"dllist":%u|b%"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ %string|unicode%(3) "hai"
+ [1]=>
+ %string|unicode%(4) "thar"
+ }
+}
diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt
new file mode 100644
index 0000000..a42e6f9
--- /dev/null
+++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: SplDoublyLinkedList : offsetUnset - first element
+--CREDITS--
+PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org>
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$list->push('oh');
+$list->push('hai');
+$list->push('thar');
+echo $list->bottom() . "\n";
+$list->offsetUnset(0);
+echo $list->bottom() . "\n";
+?>
+--EXPECT--
+oh
+hai
diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt
new file mode 100644
index 0000000..0f5dac1
--- /dev/null
+++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: SplDoublyLinkedList : offsetUnset - last element
+--CREDITS--
+PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org>
+--FILE--
+<?php
+$list = new SplDoublyLinkedList();
+$list->push('oh');
+$list->push('hai');
+$list->push('thar');
+$list->offsetUnset(2);
+var_dump($list);
+?>
+--EXPECTF--
+object(SplDoublyLinkedList)#1 (2) {
+ [%u|b%"flags":%u|b%"SplDoublyLinkedList":private]=>
+ int(0)
+ [%u|b%"dllist":%u|b%"SplDoublyLinkedList":private]=>
+ array(2) {
+ [0]=>
+ %string|unicode%(2) "oh"
+ [1]=>
+ %string|unicode%(3) "hai"
+ }
+}
diff --git a/ext/spl/tests/SplFileInfo_001.phpt b/ext/spl/tests/SplFileInfo_001.phpt
new file mode 100644
index 0000000..72060f0
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_001.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Testing SplFileInfo calling the constructor twice
+--FILE--
+<?php
+$x = new splfileinfo(1);
+$x->__construct(1);
+
+echo "done!\n";
+?>
+--EXPECT--
+done!
diff --git a/ext/spl/tests/SplFileInfo_getExtension_basic.phpt b/ext/spl/tests/SplFileInfo_getExtension_basic.phpt
new file mode 100644
index 0000000..b47b6bb
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getExtension_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplFileInfo::getExtension() basic test
+--FILE--
+<?php
+$file = md5('SplFileInfo::getExtension');
+$exts = array('.txt', '.extension', '..', '.', '');
+foreach ($exts as $ext) {
+ touch($file . $ext);
+ $info = new SplFileInfo($file . $ext);
+ var_dump($info->getExtension(), pathinfo($file . $ext, PATHINFO_EXTENSION));
+}
+?>
+--CLEAN--
+<?php
+$file = md5('SplFileInfo::getExtension');
+$exts = array('.txt', '.extension', '..', '.', '');
+foreach ($exts as $ext) {
+ unlink($file . $ext);
+}
+?>
+--EXPECTF--
+string(3) "txt"
+string(3) "txt"
+string(9) "extension"
+string(9) "extension"
+string(0) ""
+string(0) ""
+string(0) ""
+string(0) ""
+string(0) ""
+string(0) ""
diff --git a/ext/spl/tests/SplFileInfo_getGroup_basic.phpt b/ext/spl/tests/SplFileInfo_getGroup_basic.phpt
new file mode 100644
index 0000000..d279935
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getGroup_basic.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: SplFileInfo test getGroup
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--FILE--
+<?php
+$filename = __DIR__ . "/SplFileInfo_getGroup_basic";
+touch($filename);
+$fileInfo = new SplFileInfo($filename);
+$expected = filegroup($filename);
+$actual = $fileInfo->getGroup();
+var_dump($expected == $actual);
+?>
+--CLEAN--
+<?php
+$filename = __DIR__ . "/SplFileInfo_getGroup_basic";
+unlink($filename);
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/SplFileInfo_getGroup_error.phpt b/ext/spl/tests/SplFileInfo_getGroup_error.phpt
new file mode 100644
index 0000000..f0db00d
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getGroup_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Spl File Info test getGroup
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+$fileInfo = new SplFileInfo('not_existing');
+var_dump($fileInfo->getGroup());
+?>
+
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getGroup(): stat failed for not_existing' in %s
+Stack trace:
+#0 %s: SplFileInfo->getGroup()
+#1 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/SplFileInfo_getInode_basic.phpt b/ext/spl/tests/SplFileInfo_getInode_basic.phpt
new file mode 100644
index 0000000..902cbb3
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getInode_basic.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: Spl File Info test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+touch ('test_file_ptfi');
+$fileInfo = new SplFileInfo('test_file_ptfi');
+$result = shell_exec('ls -i test_file_ptfi');
+var_dump($fileInfo->getInode() == $result);
+
+?>
+--CLEAN--
+<?php
+unlink('test_file_ptfi');
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/SplFileInfo_getInode_error.phpt b/ext/spl/tests/SplFileInfo_getInode_error.phpt
new file mode 100644
index 0000000..bf8efae
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getInode_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+$fileInfo = new SplFileInfo('not_existing');
+var_dump($fileInfo->getInode());
+?>
+
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getInode(): stat failed for not_existing' in %s
+Stack trace:
+#0 %s: SplFileInfo->getInode()
+#1 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/SplFileInfo_getOwner_basic.phpt b/ext/spl/tests/SplFileInfo_getOwner_basic.phpt
new file mode 100644
index 0000000..3df8e48
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getOwner_basic.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: SplFileInfo test getOwner
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--FILE--
+<?php
+$filename = __DIR__ . "/SplFileInfo_getOwner_basic";
+touch($filename);
+$fileInfo = new SplFileInfo($filename);
+$expected = fileowner($filename);
+$actual = $fileInfo->getOwner();
+var_dump($expected == $actual);
+?>
+--CLEAN--
+<?php
+$filename = __DIR__ . "/SplFileInfo_getOwner_basic";
+unlink($filename);
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/SplFileInfo_getOwner_error.phpt b/ext/spl/tests/SplFileInfo_getOwner_error.phpt
new file mode 100644
index 0000000..d5d4678
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getOwner_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Spl File Info test getOwner
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+$fileInfo = new SplFileInfo('not_existing');
+var_dump($fileInfo->getOwner());
+?>
+
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getOwner(): stat failed for not_existing' in %s
+Stack trace:
+#0 %s: SplFileInfo->getOwner()
+#1 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/SplFileInfo_getPerms_basic.phpt b/ext/spl/tests/SplFileInfo_getPerms_basic.phpt
new file mode 100644
index 0000000..e9b7bea
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getPerms_basic.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+touch ('test_file_ptfi');
+chmod('test_file_ptfi', 0557);
+$fileInfo = new SplFileInfo('test_file_ptfi');
+var_dump($fileInfo->getPerms() == 0100557);
+
+?>
+--CLEAN--
+<?php
+unlink('test_file_ptfi');
+?>
+--EXPECTF--
+bool(true)
diff --git a/ext/spl/tests/SplFileInfo_getPerms_error.phpt b/ext/spl/tests/SplFileInfo_getPerms_error.phpt
new file mode 100644
index 0000000..8e05cdf
--- /dev/null
+++ b/ext/spl/tests/SplFileInfo_getPerms_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it>
+Andrea Giorgini <agiorg@gmail.com>
+Filippo De Santis <fd@ideato.it>
+Daniel Londero <daniel.londero@gmail.com>
+Francesco Trucchia <ft@ideato.it>
+Jacopo Romei <jacopo@sviluppoagile.it>
+#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+
+//file
+$fileInfo = new SplFileInfo('not_existing');
+var_dump($fileInfo->getPerms() == 0100557);
+?>
+
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getPerms(): stat failed for %s' in %s
+Stack trace:
+#0 %s: SplFileInfo->getPerms()
+#1 {main}
+ thrown in %s
diff --git a/ext/spl/tests/SplFileObject_current_basic.phpt b/ext/spl/tests/SplFileObject_current_basic.phpt
new file mode 100644
index 0000000..d3f4802
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_current_basic.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: SplFileObject::current basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+echo $s->current();
+
+?>
+--EXPECT--
+<?php
diff --git a/ext/spl/tests/SplFileObject_current_error001.phpt b/ext/spl/tests/SplFileObject_current_error001.phpt
new file mode 100644
index 0000000..23c1266
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_current_error001.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplFileObject::current variation error
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+$s->seek(2);
+
+echo $s->current('foo');
+?>
+--EXPECTF--
+Warning: SplFileObject::current() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_current_variation001.phpt b/ext/spl/tests/SplFileObject_current_variation001.phpt
new file mode 100644
index 0000000..0cc588a
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_current_variation001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: SplFileObject::current variation
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+$s->seek(2);
+
+echo $s->current();
+echo $s->current();
+?>
+--EXPECT--
+//line 3
+//line 3
diff --git a/ext/spl/tests/SplFileObject_fflush_basic_001.phpt b/ext/spl/tests/SplFileObject_fflush_basic_001.phpt
new file mode 100644
index 0000000..2d8a9c8
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fflush_basic_001.phpt
@@ -0,0 +1,38 @@
+--TEST--
+SplFileObject::fflush function - basic test
+--FILE--
+<?php
+/*
+ * test a successful flush
+*/
+$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv');
+var_dump($obj->fflush());
+
+/*
+ * test a unsuccessful flush
+*/
+//create a basic stream class
+class VariableStream {
+ var $position;
+ var $varname;
+
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ return true;
+ }
+
+ function url_stat() {
+ }
+}
+stream_wrapper_register("SPLtest", "VariableStream");
+$ftruncate_test = "";
+//end creating stream
+
+//open an SplFileObject using the above test stream
+$obj = New SplFileObject("SPLtest://ftruncate_test");
+var_dump($obj->fflush());
+
+?>
+--EXPECTF--
+bool(true)
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt
new file mode 100644
index 0000000..abfe5f2
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SplFileObject::fgetcsv default path
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fputcsv($fp, array(
+ 'field1',
+ 'field2',
+ 'field3',
+ 5
+));
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv());
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(6) "field1"
+ [1]=>
+ string(6) "field2"
+ [2]=>
+ string(6) "field3"
+ [3]=>
+ string(1) "5"
+}
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt
new file mode 100644
index 0000000..32705f0
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fputcsv($fp, array(
+ 'field1',
+ 'field2',
+ 'field3',
+ 5
+), '|');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv('|'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(6) "field1"
+ [1]=>
+ string(6) "field2"
+ [2]=>
+ string(6) "field3"
+ [3]=>
+ string(1) "5"
+}
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt
new file mode 100644
index 0000000..942c761
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fputcsv($fp, array(
+ 'field1',
+ 'field2',
+ 'field3',
+ 5
+), '|');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv('invalid'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::fgetcsv(): delimiter must be a character in %s on line %d
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt
new file mode 100644
index 0000000..ee24972
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fputcsv($fp, array(
+ 'field1',
+ 'field2',
+ 'field3',
+ 5
+), ',', '"');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv(',', '"'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(6) "field1"
+ [1]=>
+ string(6) "field2"
+ [2]=>
+ string(6) "field3"
+ [3]=>
+ string(1) "5"
+}
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt
new file mode 100644
index 0000000..5430e53
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fputcsv($fp, array(
+ 'field1',
+ 'field2',
+ 'field3',
+ 5
+), ',', '"');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv(',', 'invalid'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::fgetcsv(): enclosure must be a character in %s on line %d
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt
new file mode 100644
index 0000000..96c0290
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fwrite($fp, '"aaa","b""bb","ccc"');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv(',', '"', '"'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+array(3) {
+ [0]=>
+ string(3) "aaa"
+ [1]=>
+ string(4) "b"bb"
+ [2]=>
+ string(3) "ccc"
+}
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt
new file mode 100644
index 0000000..c628ac0
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SplFileObject::fgetcsv with default escape character
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fwrite($fp, '"aa\"","bb","\"c"');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv());
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+array(3) {
+ [0]=>
+ string(4) "aa\""
+ [1]=>
+ string(2) "bb"
+ [2]=>
+ string(3) "\"c"
+}
diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt
new file mode 100644
index 0000000..a570318
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplFileObject::fgetcsv with alternative delimeter
+--FILE--
+<?php
+$fp = fopen('SplFileObject__fgetcsv.csv', 'w+');
+fwrite($fp, '"aaa","b""bb","ccc"');
+fclose($fp);
+
+$fo = new SplFileObject('SplFileObject__fgetcsv.csv');
+var_dump($fo->fgetcsv(',', '"', 'invalid'));
+?>
+--CLEAN--
+<?php
+unlink('SplFileObject__fgetcsv.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::fgetcsv(): escape must be a character in %s on line %d
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_fpassthru_basic.phpt b/ext/spl/tests/SplFileObject_fpassthru_basic.phpt
new file mode 100644
index 0000000..55b7481
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fpassthru_basic.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SplFileObject::fpassthru function - basic functionality test
+--FILE--
+<?php
+$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv');
+$obj->fpassthru();
+?>
+--EXPECT--
+first,second,third
+1,2,3
+4,5,6
+7,8,9
+0,0,0
diff --git a/ext/spl/tests/SplFileObject_fputcsv.phpt b/ext/spl/tests/SplFileObject_fputcsv.phpt
new file mode 100644
index 0000000..66fdbfd
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv.phpt
@@ -0,0 +1,106 @@
+--TEST--
+SplFileObject::fputcsv(): functionality tests
+--FILE--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+$fo = new SplFileObject($file, 'w');
+
+$list = array (
+ 0 => 'aaa,bbb',
+ 1 => 'aaa,"bbb"',
+ 2 => '"aaa","bbb"',
+ 3 => 'aaa,bbb',
+ 4 => '"aaa",bbb',
+ 5 => '"aaa", "bbb"',
+ 6 => ',',
+ 7 => 'aaa,',
+ 8 => ',"aaa"',
+ 9 => '"",""',
+ 10 => '"""""",',
+ 11 => '""""",aaa',
+ 12 => 'aaa,bbb ',
+ 13 => 'aaa,"bbb "',
+ 14 => 'aaa"aaa","bbb"bbb',
+ 15 => 'aaa"aaa""",bbb',
+ 16 => 'aaa,"\\"bbb,ccc',
+ 17 => 'aaa"\\"a","bbb"',
+ 18 => '"\\"","aaa"',
+ 19 => '"\\""",aaa',
+);
+
+foreach ($list as $v) {
+ $fo->fputcsv(explode(',', $v));
+}
+unset($fo);
+
+$res = file($file);
+foreach($res as &$val)
+{
+ $val = substr($val, 0, -1);
+}
+echo '$list = ';var_export($res);echo ";\n";
+
+$fp = fopen($file, "r");
+$res = array();
+while($l=fgetcsv($fp))
+{
+ $res[] = join(',',$l);
+}
+fclose($fp);
+
+echo '$list = ';var_export($res);echo ";\n";
+
+?>
+===DONE===
+<?php exit(0); ?>
+--CLEAN--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+unlink($file);
+?>
+--EXPECT--
+$list = array (
+ 0 => 'aaa,bbb',
+ 1 => 'aaa,"""bbb"""',
+ 2 => '"""aaa""","""bbb"""',
+ 3 => 'aaa,bbb',
+ 4 => '"""aaa""",bbb',
+ 5 => '"""aaa"""," ""bbb"""',
+ 6 => ',',
+ 7 => 'aaa,',
+ 8 => ',"""aaa"""',
+ 9 => '"""""",""""""',
+ 10 => '"""""""""""""",',
+ 11 => '"""""""""""",aaa',
+ 12 => 'aaa,"bbb "',
+ 13 => 'aaa,"""bbb """',
+ 14 => '"aaa""aaa""","""bbb""bbb"',
+ 15 => '"aaa""aaa""""""",bbb',
+ 16 => 'aaa,"""\\"bbb",ccc',
+ 17 => '"aaa""\\"a""","""bbb"""',
+ 18 => '"""\\"""","""aaa"""',
+ 19 => '"""\\"""""",aaa',
+);
+$list = array (
+ 0 => 'aaa,bbb',
+ 1 => 'aaa,"bbb"',
+ 2 => '"aaa","bbb"',
+ 3 => 'aaa,bbb',
+ 4 => '"aaa",bbb',
+ 5 => '"aaa", "bbb"',
+ 6 => ',',
+ 7 => 'aaa,',
+ 8 => ',"aaa"',
+ 9 => '"",""',
+ 10 => '"""""",',
+ 11 => '""""",aaa',
+ 12 => 'aaa,bbb ',
+ 13 => 'aaa,"bbb "',
+ 14 => 'aaa"aaa","bbb"bbb',
+ 15 => 'aaa"aaa""",bbb',
+ 16 => 'aaa,"\\"bbb,ccc',
+ 17 => 'aaa"\\"a","bbb"',
+ 18 => '"\\"","aaa"',
+ 19 => '"\\""",aaa',
+);
+===DONE===
diff --git a/ext/spl/tests/SplFileObject_fputcsv_002.phpt b/ext/spl/tests/SplFileObject_fputcsv_002.phpt
new file mode 100644
index 0000000..db17493
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_002.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SplFileObject::fputcsv(): Checking data after calling the function
+--FILE--
+<?php
+$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w');
+
+$data = array(1, 2, 'foo', 'haha', array(4, 5, 6), 1.3, null);
+
+$fo->fputcsv($data);
+
+var_dump($data);
+?>
+--CLEAN--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+unlink($file);
+?>
+--EXPECTF--
+Notice: Array to string conversion in %s on line %d
+array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(3) "foo"
+ [3]=>
+ string(4) "haha"
+ [4]=>
+ array(3) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(5)
+ [2]=>
+ int(6)
+ }
+ [5]=>
+ float(1.3)
+ [6]=>
+ NULL
+}
diff --git a/ext/spl/tests/SplFileObject_fputcsv_error.phpt b/ext/spl/tests/SplFileObject_fputcsv_error.phpt
new file mode 100644
index 0000000..8368e42
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_error.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SplFileObject::fputcsv(): error conditions
+--FILE--
+<?php
+$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w');
+
+echo "*** Testing error conditions ***\n";
+// zero argument
+echo "-- Testing fputcsv() with zero argument --\n";
+var_dump( $fo->fputcsv() );
+
+// more than expected no. of args
+echo "-- Testing fputcsv() with more than expected number of arguments --\n";
+$fields = array("fld1", "fld2");
+$delim = ";";
+$enclosure ="\"";
+var_dump( $fo->fputcsv($fields, $delim, $enclosure, $fo) );
+
+echo "Done\n";
+--CLEAN--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+unlink($file);
+?>
+--EXPECTF--
+*** Testing error conditions ***
+-- Testing fputcsv() with zero argument --
+
+Warning: SplFileObject::fputcsv() expects at least 1 parameter, 0 given in %s on line %d
+NULL
+-- Testing fputcsv() with more than expected number of arguments --
+
+Warning: SplFileObject::fputcsv() expects at most 3 parameters, 4 given in %s on line %d
+NULL
+Done
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt
new file mode 100644
index 0000000..6780b24
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt
@@ -0,0 +1,826 @@
+--TEST--
+Test fputcsv() : usage variations - with all parameters specified
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when all its parameters are provided */
+
+echo "*** Testing fputcsv() : with all parameters specified ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water','fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation1.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+
+ var_dump( $fo->fputcsv($csv_field, $delimiter, $enclosure) );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with all parameters specified ***
+
+-- file opened in r+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in a+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in w+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in x+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in r+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in r+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in a+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in a+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in a+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in w+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in w+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in w+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in x+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in x+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in x+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in r+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in r+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in r+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in a+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in a+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in a+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in w+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in w+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in w+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in x+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in x+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in x+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt
new file mode 100644
index 0000000..08a2461
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt
@@ -0,0 +1,327 @@
+--TEST--
+SplFileObject::fputcsv(): Usage variations -- with line without any CSV fields
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when the field has no CSV format */
+
+echo "*** Testing fputcsv() : with no CSV format in the field ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+
+$fields = array( array('water_fruit\n'),
+ array("water_fruit\n"),
+ array("")
+ );
+
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation10.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($fields as $field) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $csv_field = $field;
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field) );
+
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with no CSV format in the field ***
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water_fruit\n"
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water_fruit\n"
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water_fruit\n"
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water_fruit\n"
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water_fruit\n"
+"
+
+-- file opened in r+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in r+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in r+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water_fruit
+"
+"
+
+-- file opened in a+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in a+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in a+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water_fruit
+"
+"
+
+-- file opened in w+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in w+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in w+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water_fruit
+"
+"
+
+-- file opened in x+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in x+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water_fruit
+"
+"
+
+-- file opened in x+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water_fruit
+"
+"
+
+-- file opened in r+ --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in r+b --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in r+t --
+int(1)
+int(1)
+bool(false)
+string(%d) "
+"
+
+-- file opened in a+ --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in a+b --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in a+t --
+int(1)
+int(1)
+bool(false)
+string(%d) "
+"
+
+-- file opened in w+ --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in w+b --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in w+t --
+int(1)
+int(1)
+bool(false)
+string(%d) "
+"
+
+-- file opened in x+ --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in x+b --
+int(1)
+int(1)
+bool(false)
+string(1) "
+"
+
+-- file opened in x+t --
+int(1)
+int(1)
+bool(false)
+string(%d) "
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt
new file mode 100644
index 0000000..c85dd0a
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt
@@ -0,0 +1,826 @@
+--TEST--
+SplFileObject::fputcsv(): Usage variations -- with default enclosure value
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when default enclosure value is provided */
+
+echo "*** Testing fputcsv() : with default enclosure value ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water,fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation11.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field, $delimiter) );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with default enclosure value ***
+
+-- file opened in r+ --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in r+b --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in r+t --
+int(14)
+int(14)
+bool(false)
+string(%d) ""water,fruit"
+"
+
+-- file opened in a+ --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in a+b --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in a+t --
+int(14)
+int(14)
+bool(false)
+string(%d) ""water,fruit"
+"
+
+-- file opened in w+ --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in w+b --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in w+t --
+int(14)
+int(14)
+bool(false)
+string(%d) ""water,fruit"
+"
+
+-- file opened in x+ --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in x+b --
+int(14)
+int(14)
+bool(false)
+string(14) ""water,fruit"
+"
+
+-- file opened in x+t --
+int(14)
+int(14)
+bool(false)
+string(%d) ""water,fruit"
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""&water&:&fruit&"
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""&water&:&fruit&"
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""&water&:&fruit&"
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""&water&:&fruit&"
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""&water&:&fruit&"
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""=water===fruit="
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""=water===fruit="
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""=water===fruit="
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""=water===fruit="
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""=water===fruit="
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) ""-water--fruit-air"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) ""-water--fruit-air"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) ""-water--fruit-air"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) ""-water--fruit-air"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) ""-water--fruit-air"
+"
+
+-- file opened in r+ --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in r+b --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in r+t --
+int(24)
+int(24)
+bool(false)
+string(%d) ""-water---fruit---air-"
+"
+
+-- file opened in a+ --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in a+b --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in a+t --
+int(24)
+int(24)
+bool(false)
+string(%d) ""-water---fruit---air-"
+"
+
+-- file opened in w+ --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in w+b --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in w+t --
+int(24)
+int(24)
+bool(false)
+string(%d) ""-water---fruit---air-"
+"
+
+-- file opened in x+ --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in x+b --
+int(24)
+int(24)
+bool(false)
+string(24) ""-water---fruit---air-"
+"
+
+-- file opened in x+t --
+int(24)
+int(24)
+bool(false)
+string(%d) ""-water---fruit---air-"
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt
new file mode 100644
index 0000000..8bb47d3
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt
@@ -0,0 +1,827 @@
+--TEST--
+SplFileObject::fputcsv(): Usage variations -- with default enclosure and different delimiter
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when default enclosure value and delimiter value
+ other than that in the field is provided */
+
+echo "*** Testing fputcsv() : with default enclosure and different delimiter value ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water,fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation12.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field, '+') );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with default enclosure and different delimiter value ***
+
+-- file opened in r+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in a+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in w+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in x+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt
new file mode 100644
index 0000000..b7c2a63
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Test fputcsv() : usage variations - with default enclosure & delimiter of two chars
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when default enclosure value and delimiter
+ of two chars is provided */
+
+echo "*** Testing fputcsv() : with default enclosure & delimiter of two chars ***\n";
+
+$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w');
+
+var_dump($fo->fputcsv(array('water', 'fruit'), ',,', '"'));
+
+unset($fo);
+
+echo "Done\n";
+?>
+--CLEAN--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+unlink($file);
+?>
+--EXPECTF--
+*** Testing fputcsv() : with default enclosure & delimiter of two chars ***
+
+Warning: SplFileObject::fputcsv(): delimiter must be a character in %s on line %d
+bool(false)
+Done
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt
new file mode 100644
index 0000000..f8cda0e
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Test fputcsv() : usage variations - with enclosure & delimiter of two chars
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when default enclosure value and delimiter
+ of two chars is provided and file is opened in read only mode */
+
+echo "*** Testing fputcsv() : with enclosure & delimiter of two chars and file opened in read mode ***\n";
+
+$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w');
+
+var_dump($fo->fputcsv(array('water', 'fruit'), ',,', '""'));
+
+unset($fo);
+
+echo "Done\n";
+?>
+--CLEAN--
+<?php
+$file = __DIR__ . '/SplFileObject_fputcsv.csv';
+unlink($file);
+?>
+--EXPECTF--
+*** Testing fputcsv() : with enclosure & delimiter of two chars and file opened in read mode ***
+
+Warning: SplFileObject::fputcsv(): enclosure must be a character in %s on line %d
+bool(false)
+Done
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt
new file mode 100644
index 0000000..9c4c01f
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt
@@ -0,0 +1,826 @@
+--TEST--
+Test fputcsv() : usage variations - with default arguments value
+--FILE--
+<?php
+
+/* Testing fputcsv() to write to a file when default arguments values are considered */
+
+echo "*** Testing fputcsv() : with default arguments value ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water','fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation5.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field) );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with default arguments value ***
+
+-- file opened in r+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in a+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in w+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in x+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) ""^water^ ^fruit^"
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) ""^water^ ^fruit^"
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) ""&""""""""&:&""&:,:"":&,&:,,,,"
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt
new file mode 100644
index 0000000..6cbb880
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt
@@ -0,0 +1,829 @@
+--TEST--
+Test fputcsv() : usage variations - with different delimiter and enclosure
+--FILE--
+<?php
+
+/*
+ Testing fputcsv() to write to a file when delimiter are different from those
+ present in the field to be written to the file
+ */
+
+echo "*** Testing fputcsv() : with different delimiter and enclosure ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water,fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation6.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field, '+', '%') );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with different delimiter and enclosure ***
+
+-- file opened in r+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in r+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in a+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in a+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in w+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in w+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in x+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water,fruit
+"
+
+-- file opened in x+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water,fruit
+"
+
+-- file opened in r+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in r+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in r+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water","fruit
+"
+
+-- file opened in a+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in a+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in a+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water","fruit
+"
+
+-- file opened in w+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in w+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in w+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water","fruit
+"
+
+-- file opened in x+ --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in x+b --
+int(15)
+int(15)
+bool(false)
+string(15) ""water","fruit
+"
+
+-- file opened in x+t --
+int(15)
+int(15)
+bool(false)
+string(%d) ""water","fruit
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water","fruit"
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water","fruit"
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water","fruit"
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) ""water","fruit"
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) ""water","fruit"
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "%^water^ ^fruit^%
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "%^water^ ^fruit^%
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "%^water^ ^fruit^%
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "%^water^ ^fruit^%
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "%^water^ ^fruit^%
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "&water&:&fruit&
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "&water&:&fruit&
+"
+
+-- file opened in r+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in r+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in a+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in a+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in w+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in w+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in x+ --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+b --
+int(16)
+int(16)
+bool(false)
+string(16) "=water===fruit=
+"
+
+-- file opened in x+t --
+int(16)
+int(16)
+bool(false)
+string(%d) "=water===fruit=
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "-water--fruit-air
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "-water--fruit-air
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "-water---fruit---air-
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "-water---fruit---air-
+"
+
+-- file opened in r+ --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in r+b --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in r+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in a+ --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in a+b --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in a+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in w+ --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in w+b --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in w+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in x+ --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in x+b --
+int(24)
+int(24)
+bool(false)
+string(24) "&""""&:&"&:,:":&,&:,,,,
+"
+
+-- file opened in x+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "&""""&:&"&:,:":&,&:,,,,
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt
new file mode 100644
index 0000000..ceb438a
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt
@@ -0,0 +1,829 @@
+--TEST--
+Test fputcsv() : usage variations - with different delimiter and same enclosure
+--FILE--
+<?php
+
+/*
+ Testing fputcsv() to write to a file when enclosure is same but delimiter is different from those
+ present in the field to be written to the file
+ */
+
+echo "*** Testing fputcsv() : with different delimiter and same enclosure ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water','fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation7.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field, '+', $enclosure) );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with different delimiter and same enclosure ***
+
+-- file opened in r+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in r+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in r+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water+fruit
+"
+
+-- file opened in a+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in a+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in a+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water+fruit
+"
+
+-- file opened in w+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in w+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in w+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water+fruit
+"
+
+-- file opened in x+ --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in x+b --
+int(12)
+int(12)
+bool(false)
+string(12) "water+fruit
+"
+
+-- file opened in x+t --
+int(12)
+int(12)
+bool(false)
+string(%d) "water+fruit
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) """"water"",""fruit"
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) """"water"",""fruit"
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) """"water"",""fruit"""
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) """"water"",""fruit"""
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "^^^water^^ ^^fruit^^^
+"
+
+-- file opened in r+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in a+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in w+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+ --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+b --
+int(22)
+int(22)
+bool(false)
+string(22) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in x+t --
+int(22)
+int(22)
+bool(false)
+string(%d) "&&&water&&:&&fruit&&&
+"
+
+-- file opened in r+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in r+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in r+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in a+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in a+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in a+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in w+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in w+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in w+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in x+ --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in x+b --
+int(23)
+int(23)
+bool(false)
+string(23) "===water======fruit===
+"
+
+-- file opened in x+t --
+int(23)
+int(23)
+bool(false)
+string(%d) "===water======fruit===
+"
+
+-- file opened in r+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in r+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in r+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in a+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in a+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in a+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in w+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in w+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in w+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in x+ --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in x+b --
+int(24)
+int(24)
+bool(false)
+string(24) "---water----fruit--air-
+"
+
+-- file opened in x+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "---water----fruit--air-
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) "---water------fruit------air---
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "---water------fruit------air---
+"
+
+-- file opened in r+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in r+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in r+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in a+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in w+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+ --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+b --
+int(32)
+int(32)
+bool(false)
+string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+
+-- file opened in x+t --
+int(32)
+int(32)
+bool(false)
+string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,&
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt
new file mode 100644
index 0000000..f1a8cbf
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt
@@ -0,0 +1,829 @@
+--TEST--
+Test fputcsv() : usage variations - with same delimiter and different enclosure
+--FILE--
+<?php
+
+/*
+ Testing fputcsv() to write to a file when delimiter is same but enclosure is different from those
+ present in the field to be written to the file
+ */
+
+echo "*** Testing fputcsv() : with same delimiter and different enclosure ***\n";
+
+/* the array is with three elements in it. Each element should be read as
+ 1st element is delimiter, 2nd element is enclosure
+ and 3rd element is csv fields
+*/
+$csv_lists = array (
+ array(',', '"', array('water,fruit') ),
+ array(',', '"', array('"water","fruit') ),
+ array(',', '"', array('"water","fruit"') ),
+ array(' ', '^', array('^water^ ^fruit^')),
+ array(':', '&', array('&water&:&fruit&')),
+ array('=', '=', array('=water===fruit=')),
+ array('-', '-', array('-water--fruit-air')),
+ array('-', '-', array('-water---fruit---air-')),
+ array(':', '&', array('&""""&:&"&:,:":&,&:,,,,'))
+
+);
+$file_path = dirname(__FILE__);
+$file = "$file_path/fputcsv_variation8.tmp";
+
+$file_modes = array ("r+", "r+b", "r+t",
+ "a+", "a+b", "a+t",
+ "w+", "w+b", "w+t",
+ "x+", "x+b", "x+t");
+
+$loop_counter = 1;
+foreach ($csv_lists as $csv_list) {
+ for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) {
+
+ echo "\n-- file opened in $file_modes[$mode_counter] --\n";
+ // create the file and add the content with has csv fields
+ if ( strstr($file_modes[$mode_counter], "r") ) {
+ $fo = new SplFileObject($file, 'w');
+ } else {
+ $fo = new SplFileObject($file, $file_modes[$mode_counter]);
+ }
+ $delimiter = $csv_list[0];
+ $enclosure = $csv_list[1];
+ $csv_field = $csv_list[2];
+
+ // write to a file in csv format
+ var_dump( $fo->fputcsv($csv_field, $delimiter, '+') );
+ // check the file pointer position and eof
+ var_dump( $fo->ftell() );
+ var_dump( $fo->eof() );
+ //close the file
+ unset($fo);
+
+ // print the file contents
+ var_dump( file_get_contents($file) );
+
+ //delete file
+ unlink($file);
+ } //end of mode loop
+} // end of foreach
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing fputcsv() : with same delimiter and different enclosure ***
+
+-- file opened in r+ --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in r+b --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in r+t --
+int(14)
+int(14)
+bool(false)
+string(%d) "+water,fruit+
+"
+
+-- file opened in a+ --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in a+b --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in a+t --
+int(14)
+int(14)
+bool(false)
+string(%d) "+water,fruit+
+"
+
+-- file opened in w+ --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in w+b --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in w+t --
+int(14)
+int(14)
+bool(false)
+string(%d) "+water,fruit+
+"
+
+-- file opened in x+ --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in x+b --
+int(14)
+int(14)
+bool(false)
+string(14) "+water,fruit+
+"
+
+-- file opened in x+t --
+int(14)
+int(14)
+bool(false)
+string(%d) "+water,fruit+
+"
+
+-- file opened in r+ --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in r+b --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in r+t --
+int(17)
+int(17)
+bool(false)
+string(%d) "+"water","fruit+
+"
+
+-- file opened in a+ --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in a+b --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in a+t --
+int(17)
+int(17)
+bool(false)
+string(%d) "+"water","fruit+
+"
+
+-- file opened in w+ --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in w+b --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in w+t --
+int(17)
+int(17)
+bool(false)
+string(%d) "+"water","fruit+
+"
+
+-- file opened in x+ --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in x+b --
+int(17)
+int(17)
+bool(false)
+string(17) "+"water","fruit+
+"
+
+-- file opened in x+t --
+int(17)
+int(17)
+bool(false)
+string(%d) "+"water","fruit+
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+"water","fruit"+
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+"water","fruit"+
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+"water","fruit"+
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+"water","fruit"+
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+"water","fruit"+
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+^water^ ^fruit^+
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+^water^ ^fruit^+
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+^water^ ^fruit^+
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+^water^ ^fruit^+
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+^water^ ^fruit^+
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+&water&:&fruit&+
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+&water&:&fruit&+
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+&water&:&fruit&+
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+&water&:&fruit&+
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+&water&:&fruit&+
+"
+
+-- file opened in r+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in r+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in r+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+=water===fruit=+
+"
+
+-- file opened in a+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in a+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in a+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+=water===fruit=+
+"
+
+-- file opened in w+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in w+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in w+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+=water===fruit=+
+"
+
+-- file opened in x+ --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in x+b --
+int(18)
+int(18)
+bool(false)
+string(18) "+=water===fruit=+
+"
+
+-- file opened in x+t --
+int(18)
+int(18)
+bool(false)
+string(%d) "+=water===fruit=+
+"
+
+-- file opened in r+ --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in r+b --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in r+t --
+int(20)
+int(20)
+bool(false)
+string(%d) "+-water--fruit-air+
+"
+
+-- file opened in a+ --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in a+b --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in a+t --
+int(20)
+int(20)
+bool(false)
+string(%d) "+-water--fruit-air+
+"
+
+-- file opened in w+ --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in w+b --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in w+t --
+int(20)
+int(20)
+bool(false)
+string(%d) "+-water--fruit-air+
+"
+
+-- file opened in x+ --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in x+b --
+int(20)
+int(20)
+bool(false)
+string(20) "+-water--fruit-air+
+"
+
+-- file opened in x+t --
+int(20)
+int(20)
+bool(false)
+string(%d) "+-water--fruit-air+
+"
+
+-- file opened in r+ --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in r+b --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in r+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "+-water---fruit---air-+
+"
+
+-- file opened in a+ --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in a+b --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in a+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "+-water---fruit---air-+
+"
+
+-- file opened in w+ --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in w+b --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in w+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "+-water---fruit---air-+
+"
+
+-- file opened in x+ --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in x+b --
+int(24)
+int(24)
+bool(false)
+string(24) "+-water---fruit---air-+
+"
+
+-- file opened in x+t --
+int(24)
+int(24)
+bool(false)
+string(%d) "+-water---fruit---air-+
+"
+
+-- file opened in r+ --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in r+b --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in r+t --
+int(26)
+int(26)
+bool(false)
+string(%d) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in a+ --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in a+b --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in a+t --
+int(26)
+int(26)
+bool(false)
+string(%d) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in w+ --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in w+b --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in w+t --
+int(26)
+int(26)
+bool(false)
+string(%d) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in x+ --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in x+b --
+int(26)
+int(26)
+bool(false)
+string(26) "+&""""&:&"&:,:":&,&:,,,,+
+"
+
+-- file opened in x+t --
+int(26)
+int(26)
+bool(false)
+string(%d) "+&""""&:&"&:,:":&,&:,,,,+
+"
+Done
+
diff --git a/ext/spl/tests/SplFileObject_fscanf_basic.phpt b/ext/spl/tests/SplFileObject_fscanf_basic.phpt
new file mode 100644
index 0000000..5279039
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fscanf_basic.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFileObject::fscanf function - basic functionality test
+--FILE--
+<?php
+$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv');
+var_dump($obj->fscanf('%s'));
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ string(18) "first,second,third"
+}
diff --git a/ext/spl/tests/SplFileObject_fseek_error_001.phpt b/ext/spl/tests/SplFileObject_fseek_error_001.phpt
new file mode 100644
index 0000000..0efeb98
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fseek_error_001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFileObject::fseek function - parameters test
+--FILE--
+<?php
+$obj = New SplFileObject(__FILE__);
+$obj->fseek(1,2,3);
+$obj->fseek();
+?>
+--EXPECTF--
+Warning: SplFileObject::fseek() expects at most 2 parameters, 3 given %s
+
+Warning: SplFileObject::fseek() expects at least 1 parameter, 0 given %s
diff --git a/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt b/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt
new file mode 100644
index 0000000..a2eef60
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SplFileObject::ftruncate function - truncating with stream that does not support truncation
+--FILE--
+<?php
+
+//create a basic stream class
+class VariableStream {
+ var $position;
+ var $varname;
+
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ return true;
+ }
+
+ function url_stat() {
+ }
+}
+stream_wrapper_register("SPLtest", "VariableStream");
+$ftruncate_test = "";
+//end creating stream
+
+//open an SplFileObject using the above test stream
+$obj = New SplFileObject("SPLtest://ftruncate_test");
+try {
+ $obj->ftruncate(1);
+} catch (LogicException $e) {
+ echo($e->getMessage());
+}
+?>
+--EXPECTF--
+Can't truncate file %s
diff --git a/ext/spl/tests/SplFileObject_fwrite_error_001.phpt b/ext/spl/tests/SplFileObject_fwrite_error_001.phpt
new file mode 100644
index 0000000..296a1f3
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fwrite_error_001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFileObject::fpassthru function - parameters test
+--FILE--
+<?php
+$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv');
+$obj->fwrite();
+$obj->fwrite('6,6,6',25,null);
+?>
+--EXPECTF--
+Warning: SplFileObject::fwrite() expects at least 1 parameter, 0 given in %s
+
+Warning: SplFileObject::fwrite() expects at most 2 parameters, 3 given in %s
diff --git a/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt b/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt
new file mode 100644
index 0000000..61741a8
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SplFileObject::fwrite function - writing with two parameters length < input string length
+--FILE--
+<?php
+$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_001.txt';
+if(file_exists($file)) {
+ unlink($file);
+}
+$obj = New SplFileObject($file,'w');
+$obj->fwrite('test_write',4);
+var_dump(file_get_contents($file));
+?>
+--CLEAN--
+<?php
+$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_001.txt';
+if(file_exists($file)) {
+ unlink($file);
+}
+?>
+--EXPECT--
+string(4) "test"
diff --git a/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt b/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt
new file mode 100644
index 0000000..31399a0
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SplFileObject::fwrite function - writing with two parameters, length > input string length
+--FILE--
+<?php
+$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_002.txt';
+if(file_exists($file)) {
+ unlink($file);
+}
+$obj = New SplFileObject($file,'w');
+$obj->fwrite('test_write',12);
+var_dump(file_get_contents($file));
+?>
+--CLEAN--
+<?php
+$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_002.txt';
+if(file_exists($file)) {
+ unlink($file);
+}
+?>
+--EXPECT--
+string(10) "test_write"
diff --git a/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt b/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt
new file mode 100644
index 0000000..e21f08f
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SplFileObject::getCsvControl function - basic test
+--FILE--
+<?php
+$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv');
+var_dump($obj->getCsvControl());
+
+?>
+--EXPECTF--
+array(2) {
+ [0]=>
+ %unicode|string%(1) ","
+ [1]=>
+ %unicode|string%(1) """
+}
diff --git a/ext/spl/tests/SplFileObject_getchildren_basic.phpt b/ext/spl/tests/SplFileObject_getchildren_basic.phpt
new file mode 100644
index 0000000..065e8ea
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getchildren_basic.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::getchildren basic
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+var_dump($s->getChildren());
+
+?>
+--EXPECT--
+NULL
diff --git a/ext/spl/tests/SplFileObject_getchildren_error001.phpt b/ext/spl/tests/SplFileObject_getchildren_error001.phpt
new file mode 100644
index 0000000..9c17a82
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getchildren_error001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::getchildren error 001
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->getChildren('string');
+
+?>
+--EXPECTF--
+Warning: SplFileObject::getChildren() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_getflags_basic.phpt b/ext/spl/tests/SplFileObject_getflags_basic.phpt
new file mode 100644
index 0000000..5addadf
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getflags_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::getFlags basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+
+file_put_contents('testdata.csv', 'eerste;tweede;derde');
+
+$fo = new SplFileObject('testdata.csv');
+
+$fo->setFlags(SplFileObject::DROP_NEW_LINE);
+var_dump($fo->getFlags());
+?>
+--CLEAN--
+<?php
+unlink('testdata.csv');
+?>
+--EXPECT--
+int(1)
diff --git a/ext/spl/tests/SplFileObject_getflags_error001.phpt b/ext/spl/tests/SplFileObject_getflags_error001.phpt
new file mode 100644
index 0000000..1602f88
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getflags_error001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: SplFileObject::getFlags error 001
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+
+file_put_contents('testdata.csv', 'eerste;tweede;derde');
+
+
+$fo = new SplFileObject('testdata.csv');
+$fo->setFlags(SplFileObject::READ_CSV);
+
+$fo->setFlags(SplFileObject::DROP_NEW_LINE);
+
+var_dump($fo->getFlags());
+
+?>
+--CLEAN--
+<?php
+unlink('testdata.csv');
+?>
+--EXPECT--
+int(1)
diff --git a/ext/spl/tests/SplFileObject_getflags_error002.phpt b/ext/spl/tests/SplFileObject_getflags_error002.phpt
new file mode 100644
index 0000000..e2c8255
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getflags_error002.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: SplFileObject::getFlags error 001
+--CREDITS--
+Erwin Poeze <erwin.poeze@gmail.com>
+--FILE--
+<?php
+
+file_put_contents('testdata.csv', 'eerste;tweede;derde');
+
+$fo = new SplFileObject('testdata.csv');
+$fo->setFlags(SplFileObject::READ_CSV);
+
+$fo->getFlags('fake');
+
+?>
+--CLEAN--
+<?php
+unlink('testdata.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::getFlags() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_getflags_variation001.phpt b/ext/spl/tests/SplFileObject_getflags_variation001.phpt
new file mode 100644
index 0000000..640de03
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_getflags_variation001.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: SplFileObject::getFlags
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+
+$fo = new SplFileObject(__FILE__);
+
+$fo->setFlags(SplFileObject::DROP_NEW_LINE);
+var_dump($fo->getFlags());
+
+$fo->setFlags(SplFileObject::READ_AHEAD);
+var_dump($fo->getFlags());
+
+$fo->setFlags(SplFileObject::SKIP_EMPTY);
+var_dump($fo->getFlags());
+
+$fo->setFlags(SplFileObject::READ_CSV);
+var_dump($fo->getFlags());
+
+?>
+--EXPECT--
+int(1)
+int(2)
+int(4)
+int(8)
diff --git a/ext/spl/tests/SplFileObject_haschildren_basic.phpt b/ext/spl/tests/SplFileObject_haschildren_basic.phpt
new file mode 100644
index 0000000..1ce00bf
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_haschildren_basic.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::haschildren basic
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+var_dump($s->hasChildren());
+
+?>
+--EXPECT--
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_haschildren_error001.phpt b/ext/spl/tests/SplFileObject_haschildren_error001.phpt
new file mode 100644
index 0000000..0c4e1de
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_haschildren_error001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::haschildren error 001
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->hasChildren('string');
+
+?>
+--EXPECTF--
+Warning: SplFileObject::hasChildren() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_key_basic.phpt b/ext/spl/tests/SplFileObject_key_basic.phpt
new file mode 100644
index 0000000..4081d31
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_key_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplFileObject::key basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(3);
+echo $s->key();
+?>
+--EXPECT--
+3
diff --git a/ext/spl/tests/SplFileObject_key_error001.phpt b/ext/spl/tests/SplFileObject_key_error001.phpt
new file mode 100644
index 0000000..b0834f0
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_key_error001.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::key error
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(12);
+$s->next();
+var_dump($s->key());
+var_dump($s->valid());
+?>
+--EXPECT--
+int(13)
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_key_error002.phpt b/ext/spl/tests/SplFileObject_key_error002.phpt
new file mode 100644
index 0000000..8fc9b7f
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_key_error002.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::key error
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(120);
+$s->next();
+var_dump($s->key());
+var_dump($s->valid());
+?>
+--EXPECT--
+int(13)
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_key_error003.phpt b/ext/spl/tests/SplFileObject_key_error003.phpt
new file mode 100644
index 0000000..7568cf5
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_key_error003.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: SplFileObject::key error
+--CREDITS--
+Erwin Poeze <erwin.poeze AT gmail.com>
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+$s->key(3);
+?>
+--EXPECTF--
+Warning: SplFileObject::key() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_next_basic.phpt b/ext/spl/tests/SplFileObject_next_basic.phpt
new file mode 100644
index 0000000..59dc7ab
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_next_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::next basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+echo $s->current();
+$s->next();
+
+echo $s->current();
+
+?>
+--EXPECT--
+<?php
+//line 2
diff --git a/ext/spl/tests/SplFileObject_next_variation001.phpt b/ext/spl/tests/SplFileObject_next_variation001.phpt
new file mode 100644
index 0000000..34771dd
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_next_variation001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: SplFileObject::next variation 001
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(13);
+echo $s->current();
+
+$s->next();
+echo $s->current();
+var_dump($s->valid());
+?>
+--EXPECT--
+?>
+bool(false)
diff --git a/ext/spl/tests/SplFileObject_next_variation002.phpt b/ext/spl/tests/SplFileObject_next_variation002.phpt
new file mode 100644
index 0000000..d48ff8c
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_next_variation002.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: SplFileObject::next variation 002, read ahead
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+$s->seek(2);
+echo $s->current();
+$s->next();
+echo $s->current();
+
+$s->setFlags(SplFileObject::READ_AHEAD);
+
+$s->seek(2);
+echo $s->current();
+$s->next();
+echo $s->current();
+?>
+--EXPECT--
+//line 3
+//line 4
+//line 3
+//line 4
diff --git a/ext/spl/tests/SplFileObject_rewind_basic.phpt b/ext/spl/tests/SplFileObject_rewind_basic.phpt
new file mode 100644
index 0000000..331c587
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_rewind_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: SplFileObject::rewind basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(3);
+
+$s->rewind();
+echo $s->current();
+?>
+--EXPECT--
+<?php
diff --git a/ext/spl/tests/SplFileObject_rewind_error001.phpt b/ext/spl/tests/SplFileObject_rewind_error001.phpt
new file mode 100644
index 0000000..bdb3301
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_rewind_error001.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: SplFileObject::rewind() with a parameter.
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+
+file_put_contents('testdata.csv', 'eerste;tweede;derde');
+
+$fo = new SplFileObject('testdata.csv');
+
+$fo->rewind( "invalid" );
+
+?>
+--EXPECTF--
+Warning: SplFileObject::rewind() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFileObject_rewind_variation001.phpt b/ext/spl/tests/SplFileObject_rewind_variation001.phpt
new file mode 100644
index 0000000..d835c44
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_rewind_variation001.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: SplFileObject::rewind variation 001
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(15);
+echo $s->current();
+$s->next();
+echo $s->current();
+var_dump($s->valid());
+$s->rewind();
+var_dump($s->valid());
+echo $s->current();
+?>
+--EXPECT--
+?>
+bool(false)
+bool(true)
+<?php
diff --git a/ext/spl/tests/SplFileObject_seek_basic.phpt b/ext/spl/tests/SplFileObject_seek_basic.phpt
new file mode 100644
index 0000000..7106f70
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_seek_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplFileObject::seek basic
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(2);
+echo $s->current();
+?>
+--EXPECT--
+//line 3
diff --git a/ext/spl/tests/SplFileObject_seek_error002.phpt b/ext/spl/tests/SplFileObject_seek_error002.phpt
new file mode 100644
index 0000000..057c8d3
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_seek_error002.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: SplFileObject::seek error 001
+--CREDITS--
+Ricardo Oedietram <ricardo@odracir.nl>
+Erwin Poeze <erwin.poeze@gmail.com>
+#PFZ June PHP TestFest 2012
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+
+$s->seek(20);
+echo $s->current();
+?>
+--EXPECT--
diff --git a/ext/spl/tests/SplFileObject_seek_error_001.phpt b/ext/spl/tests/SplFileObject_seek_error_001.phpt
new file mode 100644
index 0000000..bcf44b0
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_seek_error_001.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SplFileObject::seek function - test parameters
+--FILE--
+<?php
+$obj = New SplFileObject(__FILE__);
+$obj->seek(1,2);
+$obj->seek();
+try {
+ $obj->seek(-1);
+} catch (LogicException $e) {
+ echo($e->getMessage());
+}
+?>
+--EXPECTF--
+
+Warning: SplFileObject::seek() expects exactly 1 parameter, 2 given in %s
+
+Warning: SplFileObject::seek() expects exactly 1 parameter, 0 given in %s
+Can't seek file %s to negative line %s
diff --git a/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt b/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt
new file mode 100644
index 0000000..b263060
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: SplFileObject::setCsvControl basic
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+file_put_contents('csv_control_data.csv',
+<<<CDATA
+'groene appelen'|10
+'gele bananen'|20
+'rode kersen'|30
+CDATA
+);
+$s = new SplFileObject('csv_control_data.csv');
+$s->setFlags(SplFileObject::READ_CSV);
+$s->setCsvControl('|', '\'', '/');
+foreach ($s as $row) {
+ list($fruit, $quantity) = $row;
+ echo "$fruit : $quantity\n";
+}
+?>
+--CLEAN--
+<?php
+unlink('csv_control_data.csv');
+?>
+--EXPECT--
+groene appelen : 10
+gele bananen : 20
+rode kersen : 30
+
diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt
new file mode 100644
index 0000000..f582a4a
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: SplFileObject::setCsvControl error 001
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+file_put_contents('csv_control_data.csv',
+<<<CDATA
+'groene appelen'|10
+'gele bananen'|20
+'rode kersen'|30
+CDATA
+);
+$s = new SplFileObject('csv_control_data.csv');
+$s->setFlags(SplFileObject::READ_CSV);
+$s->setCsvControl('||');
+?>
+--CLEAN--
+<?php
+unlink('csv_control_data.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::setCsvControl(): delimiter must be a character in %s on line %d
+
diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt
new file mode 100644
index 0000000..bcfd9c4
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: SplFileObject::setCsvControl error 002
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+file_put_contents('csv_control_data.csv',
+<<<CDATA
+'groene appelen'|10
+'gele bananen'|20
+'rode kersen'|30
+CDATA
+);
+$s = new SplFileObject('csv_control_data.csv');
+$s->setFlags(SplFileObject::READ_CSV);
+$s->setCsvControl('|', 'two');
+?>
+--CLEAN--
+<?php
+unlink('csv_control_data.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::setCsvControl(): enclosure must be a character in %s on line %d
+
diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt
new file mode 100644
index 0000000..8b1f54d
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: SplFileObject::setCsvControl error 003
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--INI--
+include_path=.
+--FILE--
+<?php
+file_put_contents('csv_control_data.csv',
+<<<CDATA
+'groene appelen'|10
+'gele bananen'|20
+'rode kersen'|30
+CDATA
+);
+$s = new SplFileObject('csv_control_data.csv');
+$s->setFlags(SplFileObject::READ_CSV);
+$s->setCsvControl('|', '\'', 'three');
+?>
+--CLEAN--
+<?php
+unlink('csv_control_data.csv');
+?>
+--EXPECTF--
+Warning: SplFileObject::setCsvControl(): escape must be a character in %s on line %d
+
diff --git a/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt b/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt
new file mode 100644
index 0000000..7aaf8a3
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: SplFileObject::setCsvControl variation 001
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+file_put_contents('csv_control_data.csv',
+<<<CDATA
+"groene appelen",10
+"gele bananen",20
+"rode kersen",30
+CDATA
+);
+$s = new SplFileObject('csv_control_data.csv');
+$s->setFlags(SplFileObject::READ_CSV);
+$s->setCsvControl();
+foreach ($s as $row) {
+ list($fruit, $quantity) = $row;
+ echo "$fruit : $quantity\n";
+}
+?>
+--CLEAN--
+<?php
+unlink('csv_control_data.csv');
+?>
+--EXPECT--
+groene appelen : 10
+gele bananen : 20
+rode kersen : 30
+
diff --git a/ext/spl/tests/SplFileObject_testinput.csv b/ext/spl/tests/SplFileObject_testinput.csv
new file mode 100644
index 0000000..41a9e31
--- /dev/null
+++ b/ext/spl/tests/SplFileObject_testinput.csv
@@ -0,0 +1,5 @@
+first,second,third
+1,2,3
+4,5,6
+7,8,9
+0,0,0
diff --git a/ext/spl/tests/SplFixedArray__construct_param_array.phpt b/ext/spl/tests/SplFixedArray__construct_param_array.phpt
new file mode 100644
index 0000000..d63d7cc
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray__construct_param_array.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFixedArray::__construct() with array passed as integer.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( array("string", 1) );
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, array given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray__construct_param_float.phpt b/ext/spl/tests/SplFixedArray__construct_param_float.phpt
new file mode 100644
index 0000000..670a109
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray__construct_param_float.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SplFixedArray::__construct() with float passed as parameter.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 3.141 );
+
+echo $array->getSize();
+
+?>
+--EXPECT--
+3 \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray__construct_param_null.phpt b/ext/spl/tests/SplFixedArray__construct_param_null.phpt
new file mode 100644
index 0000000..3b1543d
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray__construct_param_null.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SplFixedArray::__construct() with null passed as parameter.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( NULL );
+
+print_r( $array );
+
+?>
+--EXPECTF--
+SplFixedArray Object
+(
+) \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray__construct_param_string.phpt b/ext/spl/tests/SplFixedArray__construct_param_string.phpt
new file mode 100644
index 0000000..3a7e734
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray__construct_param_string.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFixedArray::__construct() with string passed as parameter.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( "string" );
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, %unicode_string_optional% given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt b/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt
new file mode 100644
index 0000000..6582f84
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Create an SplFixedArray using an SplFixedArray object.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = new SplFixedArray(new SplFixedArray(3));
+var_dump($array);
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, object given in %s on line %d
+object(SplFixedArray)#1 (0) {
+} \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_count_checkParams.phpt b/ext/spl/tests/SplFixedArray_count_checkParams.phpt
new file mode 100644
index 0000000..5cbe2e8
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_count_checkParams.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Makes sure that an integer cannot be passed into the count() method of the splFixedArray.
+--CREDITS--
+PHPNW Test Fest 2009 - Rick Ogden
+--FILE--
+<?php
+$ar = new SplFixedArray(3);
+$ar[0] = 1;
+$ar[1] = 2;
+$ar[2] = 3;
+
+echo $ar->count(3);
+?>
+--EXPECTF--
+Warning: SplFixedArray::count() expects exactly 0 parameters, 1 given in %s on line %d
+
diff --git a/ext/spl/tests/SplFixedArray_count_param_int.phpt b/ext/spl/tests/SplFixedArray_count_param_int.phpt
new file mode 100644
index 0000000..108bb2d
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_count_param_int.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Creates array, uses the count function to get the size of the array, but passes a parameter.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+echo $array->count(3);
+?>
+--EXPECTF--
+Warning: SplFixedArray::count() expects exactly 0 parameters, 1 given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_current_param.phpt b/ext/spl/tests/SplFixedArray_current_param.phpt
new file mode 100644
index 0000000..71f5d3a
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_current_param.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SplFixedArray::current() with a parameter. *BUG*
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 3 );
+
+$array[0] = "Hello";
+$array[1] = "world";
+$array[2] = "elePHPant";
+
+foreach ( $array as $value ) {
+ echo $array->current( array("this","should","not","execute") );
+}
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt
new file mode 100644
index 0000000..36ecf46
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt
@@ -0,0 +1,10 @@
+--TEST--
+pass an integer into fromArray()
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+echo SplFixedArray::fromArray(17954);
+?>
+--EXPECTF--
+Warning: SplFixedArray::fromArray() expects parameter 1 to be array, integer given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt
new file mode 100644
index 0000000..ba81428
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt
@@ -0,0 +1,10 @@
+--TEST--
+pass a string into fromArray()
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+echo SplFixedArray::fromArray('hello');
+?>
+--EXPECTF--
+Warning: SplFixedArray::fromArray() expects parameter 1 to be array, %unicode_string_optional% given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt b/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt
new file mode 100644
index 0000000..034d457
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Create a SplFixedArray from an array using the fromArray() function use the default behaviour of preserve the indexes.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = SplFixedArray::fromArray(array(1 => 1,
+ 2 => '2',
+ 3 => false));
+var_dump($array);
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (4) {
+ [0]=>
+ NULL
+ [1]=>
+ int(1)
+ [2]=>
+ %string|unicode%(1) "2"
+ [3]=>
+ bool(false)
+}
diff --git a/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt b/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt
new file mode 100644
index 0000000..ecae2ab
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Create a SplFixedArray from an array using the fromArray() function don't try to preserve the indexes.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = SplFixedArray::fromArray(array(1 => 1,
+ 2 => '2',
+ 3 => false),
+ false);
+var_dump($array);
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (3) {
+ [0]=>
+ int(1)
+ [1]=>
+ %string|unicode%(1) "2"
+ [2]=>
+ bool(false)
+}
diff --git a/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt b/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt
new file mode 100644
index 0000000..80d9669
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Tries to create a SplFixedArray using a boolean value.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = SplFixedArray::fromArray(true);
+?>
+--EXPECTF--
+Warning: SplFixedArray::fromArray() expects parameter 1 to be array, boolean given in %s on line %d \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt b/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt
new file mode 100644
index 0000000..f57fe78
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Tries to create a SplFixedArray using the fromArray() function and a multi dimentional array.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = SplFixedArray::fromArray(array(array('1')));
+var_dump($array);
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ %string|unicode%(1) "1"
+ }
+}
diff --git a/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt b/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt
new file mode 100644
index 0000000..ef4f40c
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SplFixedArray::getSize() pass a parameter when none are expected
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+$fixed_array = new SplFixedArray(2);
+echo "*test* ".$fixed_array->getSize(3);
+?>
+--EXPECTF--
+Warning: SplFixedArray::getSize() expects exactly 0 parameters, 1 given in %s on line %d
+*test*
diff --git a/ext/spl/tests/SplFixedArray_key_param.phpt b/ext/spl/tests/SplFixedArray_key_param.phpt
new file mode 100644
index 0000000..300e6df
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_key_param.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SplFixedArray::key() with a parameter passed. This is a bug and an error should be called.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 3 );
+
+$array[0] = "Hello";
+$array[1] = "world";
+$array[2] = "elePHPant";
+
+foreach ( $array as $value ) {
+ echo $array->key( array("this","should","not","execute") );
+}
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_key_setsize.phpt b/ext/spl/tests/SplFixedArray_key_setsize.phpt
new file mode 100644
index 0000000..97e4811
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_key_setsize.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SplFixedArray::key() when the array has a size higher than the amount of values specified.
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 4 );
+
+$array[0] = "Hello";
+$array[1] = "world";
+$array[2] = "elePHPant";
+
+foreach ( $array as $value ) {
+ echo $array->key( );
+}
+
+?>
+--EXPECT--
+0123 \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_next_param.phpt b/ext/spl/tests/SplFixedArray_next_param.phpt
new file mode 100644
index 0000000..5e8cb63
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_next_param.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplFixedArray::next() with a parameter. *BUG*
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 4 );
+
+$array[0] = "Hello";
+$array[1] = "world";
+$array[2] = "elePHPant";
+
+$array->next( "invalid" );
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::next() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt
new file mode 100644
index 0000000..76ee2f5
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL FixedArray offsetExists throws error only one parameter
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$a = $array->offsetExists();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplFixedArray::offsetExists() expects exactly 1 parameter, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt b/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt
new file mode 100644
index 0000000..9bfda34
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SPL FixedArray offsetExists behaviour on a negative index
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+if($array->offsetExists(-10) === false) {
+ echo 'PASS';
+}
+?>
+--EXPECT--
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt
new file mode 100644
index 0000000..71a1bf8
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL FixedArray offsetGet throws error on no parameter
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$array[0] = 'a';
+$a = $array->offsetGet();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplFixedArray::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt
new file mode 100644
index 0000000..4e43a52
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL FixedArray offsetSet throws error on no parameters
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$a = $array->offsetSet();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplFixedArray::offsetSet() expects exactly 2 parameters, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt
new file mode 100644
index 0000000..c19cd01
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL FixedArray offsetSet throws error only one parameter
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$a = $array->offsetSet(2);
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplFixedArray::offsetSet() expects exactly 2 parameters, 1 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt
new file mode 100644
index 0000000..40a372b
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL FixedArray offsetUnset throws error on no parameter
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$a = $array->offsetUnset();
+if(is_null($a)) {
+ echo 'PASS';
+}
+?>
+--EXPECTF--
+Warning: SplFixedArray::offsetUnset() expects exactly 1 parameter, 0 given in %s on line %d
+PASS
diff --git a/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt b/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt
new file mode 100644
index 0000000..21976b5
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Check removing an item from an array when the offset is not an integer.
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a fixed array
+ $fixedArray = new SplFixedArray(5);
+
+ // Fill it up
+ for ($i=0; $i < 5; $i++) {
+ $fixedArray[$i] = "PHPNW Testfest";
+ }
+
+ // remove an item
+ $fixedArray->offsetUnset("4");
+
+ var_dump($fixedArray);
+
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (5) {
+ [0]=>
+ %string|unicode%(14) "PHPNW Testfest"
+ [1]=>
+ %string|unicode%(14) "PHPNW Testfest"
+ [2]=>
+ %string|unicode%(14) "PHPNW Testfest"
+ [3]=>
+ %string|unicode%(14) "PHPNW Testfest"
+ [4]=>
+ NULL
+}
diff --git a/ext/spl/tests/SplFixedArray_rewind_param.phpt b/ext/spl/tests/SplFixedArray_rewind_param.phpt
new file mode 100644
index 0000000..7002efb
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_rewind_param.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplFixedArray::rewind() with a parameter. *BUG*
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+$array = new SplFixedArray( 4 );
+
+$array[0] = "Hello";
+$array[1] = "world";
+$array[2] = "elePHPant";
+
+$array->rewind( "invalid" );
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::rewind() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt b/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt
new file mode 100644
index 0000000..a460747
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Create array, fills it with and resizes it to lower value.
+--CREDITS--
+Philip Norton philipnorton42@gmail.com
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$array[0] = 1;
+$array[1] = 1;
+$array[2] = 1;
+$array[3] = 1;
+$array[4] = 1;
+$array->setSize(2);
+var_dump($array);
+?>
+--EXPECT--
+object(SplFixedArray)#1 (2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+} \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_setSize_param_array.phpt b/ext/spl/tests/SplFixedArray_setSize_param_array.phpt
new file mode 100644
index 0000000..269a45d
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setSize_param_array.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SplFixedArray::setSize() with an array parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+$fixed_array = new SplFixedArray(2);
+$fixed_array->setSize(array());
+var_dump($fixed_array);
+?>
+--EXPECTF--
+Warning: SplFixedArray::setSize() expects parameter 1 to be long, array given in %s on line %d
+object(SplFixedArray)#1 (2) {
+ [0]=>
+ NULL
+ [1]=>
+ NULL
+}
diff --git a/ext/spl/tests/SplFixedArray_setSize_param_float.phpt b/ext/spl/tests/SplFixedArray_setSize_param_float.phpt
new file mode 100644
index 0000000..c65686c
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setSize_param_float.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SplFixedArray::setSize() with a float param
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+$fixed_array = new SplFixedArray(2);
+$fixed_array->setSize(3.14159);
+var_dump($fixed_array);
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (3) {
+ [0]=>
+ NULL
+ [1]=>
+ NULL
+ [2]=>
+ NULL
+}
diff --git a/ext/spl/tests/SplFixedArray_setSize_param_null.phpt b/ext/spl/tests/SplFixedArray_setSize_param_null.phpt
new file mode 100644
index 0000000..ddb37be
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setSize_param_null.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SplFixedArray::setSize() with a null parameter
+--CREDITS--
+PHPNW Testfest 2009 - Adrian Hardy
+--FILE--
+<?php
+$fixed_array = new SplFixedArray(2);
+$fixed_array->setSize(null);
+var_dump($fixed_array);
+?>
+--EXPECT--
+object(SplFixedArray)#1 (0) {
+}
diff --git a/ext/spl/tests/SplFixedArray_setSize_reduce.phpt b/ext/spl/tests/SplFixedArray_setSize_reduce.phpt
new file mode 100644
index 0000000..eb8e1d9
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setSize_reduce.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL FixedArray can reduce size of array
+--CREDITS--
+PHPNW TestFest 2009 - Ben Longden
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$array[0] = 'a';
+$array[1] = 'b';
+$array[2] = 'c';
+$array[3] = 'd';
+$array[4] = 'e';
+$array->setSize(3);
+print_r($array);
+?>
+--EXPECT--
+SplFixedArray Object
+(
+ [0] => a
+ [1] => b
+ [2] => c
+)
diff --git a/ext/spl/tests/SplFixedArray_setsize_001.phpt b/ext/spl/tests/SplFixedArray_setsize_001.phpt
new file mode 100644
index 0000000..925912c
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setsize_001.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: FixedArray: setsize - populate array, then shrink
+--CREDITS--
+PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org>
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$array[0] = 'one';
+$array[1] = 'two';
+$array[2] = 'three';
+$array[3] = 'four';
+$array[4] = 'five';
+$array->setSize(2);
+var_dump($array);
+?>
+--EXPECTF--
+object(SplFixedArray)#1 (2) {
+ [0]=>
+ %string|unicode%(3) "one"
+ [1]=>
+ %string|unicode%(3) "two"
+}
diff --git a/ext/spl/tests/SplFixedArray_setsize_grow.phpt b/ext/spl/tests/SplFixedArray_setsize_grow.phpt
new file mode 100644
index 0000000..418d1ac
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setsize_grow.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SplFixedArray::setSize() grow
+--CREDITS--
+PHPNW Test Fest 2009 - Jordan Hatch
+--FILE--
+<?php
+
+echo "\n";
+
+$array = new SplFixedArray(2);
+
+$array[0] = "Value 1";
+$array[1] = "Value 2";
+
+$array->setSize(4);
+
+$array[2] = "Value 3";
+$array[3] = "Value 4";
+
+print_r($array);
+
+?>
+--EXPECT--
+SplFixedArray Object
+(
+ [0] => Value 1
+ [1] => Value 2
+ [2] => Value 3
+ [3] => Value 4
+) \ No newline at end of file
diff --git a/ext/spl/tests/SplFixedArray_setsize_shrink.phpt b/ext/spl/tests/SplFixedArray_setsize_shrink.phpt
new file mode 100644
index 0000000..2130cf8
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_setsize_shrink.phpt
@@ -0,0 +1,28 @@
+--TEST--
+shrink a full array of integers
+--CREDITS--
+PHPNW Testfest 2009 - Lorna Mitchell
+--FILE--
+<?php
+$array = new SplFixedArray(5);
+$array[0] = 1;
+$array[1] = 1;
+$array[2] = 1;
+$array[3] = 1;
+$array[4] = 1;
+
+$array->setSize(4);
+var_dump($array);
+
+?>
+--EXPECT--
+object(SplFixedArray)#1 (4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+ [3]=>
+ int(1)
+}
diff --git a/ext/spl/tests/SplFixedArray_toArray_with-params.phpt b/ext/spl/tests/SplFixedArray_toArray_with-params.phpt
new file mode 100644
index 0000000..8864362
--- /dev/null
+++ b/ext/spl/tests/SplFixedArray_toArray_with-params.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Check that passing a parameter to toArray() produces a correct error
+--CREDITS--
+PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com )
+--FILE--
+<?php
+ // Create a fixed array
+ $fixedArray = new SplFixedArray(5);
+
+ // Fill it up
+ for ($i=0; $i < 5; $i++) {
+ $fixedArray[$i] = "PHPNW Testfest";
+ }
+
+ // Test count() returns correct error when parameters are passed.
+ $fixedArray->count(1);
+?>
+--EXPECTF--
+Warning: SplFixedArray::count() expects exactly 0 parameters, %d given in %s on line %d
diff --git a/ext/spl/tests/SplHeap_count_invalid_parameter.phpt b/ext/spl/tests/SplHeap_count_invalid_parameter.phpt
new file mode 100644
index 0000000..727790e
--- /dev/null
+++ b/ext/spl/tests/SplHeap_count_invalid_parameter.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Check that SplHeap::count generate a warning and returns NULL when param passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ new stdClass,
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $h = new SplMaxHeap();
+
+ var_dump($h->count($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt b/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt
new file mode 100644
index 0000000..ba03976
--- /dev/null
+++ b/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Check that SplHeap::extract generate a warning and returns NULL when param passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ new stdClass,
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $h = new SplMaxHeap();
+
+ var_dump($h->extract($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt b/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt
new file mode 100644
index 0000000..86c6b63
--- /dev/null
+++ b/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Check that SplHeap::insert generate a warning and returns NULL when $value is missing
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$h = new SplMaxHeap();
+
+var_dump($h->insert());
+
+?>
+--EXPECTF--
+Warning: SplHeap::insert() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplHeap_isEmpty.phpt b/ext/spl/tests/SplHeap_isEmpty.phpt
new file mode 100644
index 0000000..e179dbc
--- /dev/null
+++ b/ext/spl/tests/SplHeap_isEmpty.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplHeap::isEmpty standard success test
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$h = new SplMaxHeap();
+
+var_dump($h->isEmpty());
+
+?>
+--EXPECTF--
+bool(true)
+
diff --git a/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt b/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt
new file mode 100644
index 0000000..021aff4
--- /dev/null
+++ b/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Check that SplHeap::isEmpty generate a warning and returns NULL when param passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ new stdClass,
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $h = new SplMaxHeap();
+
+ var_dump($h->isEmpty($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt
new file mode 100644
index 0000000..62605b1
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Check that SplObjectStorage::addAll generate a warning and returns NULL when passed non-object param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->addAll($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt
new file mode 100644
index 0000000..d984429
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Check that SplObjectStorage::attach generates a warning and returns NULL when bad params are passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+var_dump($s->attach(true));
+var_dump($s->attach(new stdClass, true, true));
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::attach() expects parameter 1 to be object, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::attach() expects at most 2 parameters, 3 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt
new file mode 100644
index 0000000..f523928
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Check that SplObjectStorage::contains generate a warning and returns NULL when passed non-object param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->contains($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::contains() expects parameter 1 to be object, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt
new file mode 100644
index 0000000..65fa691
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplObjectStorage::current returns NULL when storage is empty
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+var_dump($s->current());
+
+?>
+--EXPECT--
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt
new file mode 100644
index 0000000..83b79fc
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Check that SplObjectStorage::detach generate a warning and returns NULL when passed non-object param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->detach($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::detach() expects parameter 1 to be object, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_getHash.phpt b/ext/spl/tests/SplObjectStorage_getHash.phpt
new file mode 100644
index 0000000..f309b3d
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_getHash.phpt
@@ -0,0 +1,60 @@
+--TEST--
+SplObjectStorage::getHash implementation
+--FILE--
+<?php
+$s = new SplObjectStorage();
+$o1 = new Stdclass;
+$o2 = new Stdclass;
+$s[$o1] = "some_value\n";
+echo $s->offsetGet($o1);
+
+class MySplObjectStorage extends SplObjectStorage {
+ public function getHash($obj) {
+ return 2;
+ }
+}
+
+try {
+ $s1 = new MySplObjectStorage;
+ $s1[$o1] = "foo";
+} catch(Exception $e) {
+ echo "caught\n";
+}
+
+class MySplObjectStorage2 extends SplObjectStorage {
+ public function getHash($obj) {
+ throw new Exception("foo");
+ return "asd";
+ }
+}
+
+try {
+ $s2 = new MySplObjectStorage2;
+ $s2[$o2] = "foo";
+} catch(Exception $e) {
+ echo "caught\n";
+}
+
+class MySplObjectStorage3 extends SplObjectStorage {
+ public function getHash($obj) {
+ return "asd";
+ }
+}
+
+$s3 = new MySplObjectStorage3;
+$s3[$o1] = $o1;
+var_dump($s3[$o1]);
+$s3[$o2] = $o2;
+
+var_dump($s3[$o1] === $s3[$o2]);
+
+?>
+===DONE===
+--EXPECT--
+some_value
+caught
+caught
+object(stdClass)#2 (0) {
+}
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt
new file mode 100644
index 0000000..e6c4de8
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplObjectStorage::getInfo returns NULL when storage is empty
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+var_dump($s->getInfo());
+
+?>
+--EXPECT--
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_offsetGet.phpt b/ext/spl/tests/SplObjectStorage_offsetGet.phpt
new file mode 100644
index 0000000..e73f6b1
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_offsetGet.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Standard success for SplObjectStorage::offsetGet
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+$o1 = new stdClass();
+$s[$o1] = 'some_value';
+
+echo $s->offsetGet($o1);
+
+?>
+--EXPECT--
+some_value
+
diff --git a/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt
new file mode 100644
index 0000000..3f8bd43
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Check that SplObjectStorage::offsetGet generate a warning and return NULL when passed non-object param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+ $o1 = new stdClass();
+ $s[$o1] = 'some_value';
+
+ var_dump($s->offsetGet($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt b/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt
new file mode 100644
index 0000000..72b032c
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Check that SplObjectStorage::offsetGet throws exception when non-existing object is requested
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+$o1 = new stdClass();
+
+try {
+ $s->offsetGet($o1);
+} catch (UnexpectedValueException $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Object not found
+
diff --git a/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt b/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt
new file mode 100644
index 0000000..7c8cb75
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Check that SplObjectStorage::removeUncommon functions when receiving proper input
+--CREDITS--
+Matthew Turland (me@matthewturland.com)
+--FILE--
+<?php
+
+ $a = (object) 'a';
+ $b = (object) 'b';
+ $c = (object) 'c';
+
+ $foo = new SplObjectStorage;
+ $foo->attach($a);
+ $foo->attach($b);
+
+ $bar = new SplObjectStorage;
+ $bar->attach($b);
+ $bar->attach($c);
+
+ $foo->removeAllExcept($bar);
+ var_dump($foo->contains($a));
+ var_dump($foo->contains($b));
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
diff --git a/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt
new file mode 100644
index 0000000..62e0dde
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Check that SplObjectStorage::removeAllExcept generate a warning and returns NULL when passed non-object param
+--CREDITS--
+Matthew Turland (me@matthewturland.com)
+Based on work done at PHPNW Testfest 2009 by Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->removeAllExcept($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt
new file mode 100644
index 0000000..ffd3398
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Check that SplObjectStorage::removeAll generate a warning and returns NULL when passed non-object param
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->removeAll($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, double given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, null given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt
new file mode 100644
index 0000000..c8c3cd1
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplObjectStorage::setInfo returns NULL when storage is empty
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+var_dump($s->setInfo('some_value'));
+
+?>
+--EXPECT--
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt
new file mode 100644
index 0000000..52f8f9b
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Check that SplObjectStorage::setInfo returns NULL when no param is passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+var_dump($s->setInfo());
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::setInfo() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt
new file mode 100644
index 0000000..a525317
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: Test that serialized blob contains unique elements (CVE-2010-2225)
+--FILE--
+<?php
+
+$badblobs = array(
+'x:i:2;i:0;,i:1;;i:0;,i:2;;m:a:0:{}',
+'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};R:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}',
+'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};r:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}',
+);
+foreach($badblobs as $blob) {
+try {
+ $so = new SplObjectStorage();
+ $so->unserialize($blob);
+ var_dump($so);
+} catch(UnexpectedValueException $e) {
+ echo $e->getMessage()."\n";
+}
+}
+--EXPECTF--
+Error at offset 6 of 34 bytes
+Error at offset 46 of 89 bytes
+object(SplObjectStorage)#2 (1) {
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#3 (0) {
+ }
+ ["inf"]=>
+ int(1)
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#1 (0) {
+ }
+ ["inf"]=>
+ object(stdClass)#3 (0) {
+ }
+ }
+ }
+}
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt
new file mode 100644
index 0000000..dcf43e2
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Check that SplObjectStorage::unserialize returns NULL when non-string param is passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ array(),
+ new stdClass(),
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ var_dump($s->unserialize($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplObjectStorage::unserialize() expects parameter 1 to be %binary_string_optional%, array given in %s on line %d
+NULL
+
+Warning: SplObjectStorage::unserialize() expects parameter 1 to be %binary_string_optional%, object given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt
new file mode 100644
index 0000000..be2bb33
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Check that SplObjectStorage::unserialize throws exception when numeric value passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ 12345,
+ 1.2345,
+ PHP_INT_MAX,
+ 'x:rubbish', // rubbish after the 'x:' prefix
+ 'x:i:2;O:8:"stdClass":0:{},s:5:"value";;m:a:0:{}',
+);
+
+foreach($data_provider as $input) {
+
+ $s = new SplObjectStorage();
+
+ try {
+ $s->unserialize($input);
+ } catch(UnexpectedValueException $e) {
+ echo $e->getMessage() . PHP_EOL;
+ }
+}
+
+?>
+--EXPECTF--
+Error at offset %d of %d bytes
+Error at offset %d of %d bytes
+Error at offset %d of %d bytes
+Error at offset %d of %d bytes
+Error at offset %d of %d bytes
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt
new file mode 100644
index 0000000..4c2dd75
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Check that SplObjectStorage::unserialize throws exception when NULL passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$s = new SplObjectStorage();
+
+try {
+ $s->unserialize(NULL);
+} catch(UnexpectedValueException $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECTF--
+Empty serialized string cannot be empty
+
diff --git a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt
new file mode 100644
index 0000000..e96a82a
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt
@@ -0,0 +1,47 @@
+--TEST--
+SPL: Test unserializing tested & linked storage
+--FILE--
+<?php
+$o = new StdClass();
+$a = new StdClass();
+
+$o->a = $a;
+
+$so = new SplObjectStorage();
+
+$so[$o] = 1;
+$so[$a] = 2;
+
+$s = serialize($so);
+echo $s."\n";
+
+$so1 = unserialize($s);
+var_dump($so1);
+
+--EXPECTF--
+C:16:"SplObjectStorage":76:{x:i:2;O:8:"stdClass":1:{s:1:"a";O:8:"stdClass":0:{}},i:1;;r:4;,i:2;;m:a:0:{}}
+object(SplObjectStorage)#4 (1) {
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#5 (1) {
+ ["a"]=>
+ object(stdClass)#6 (0) {
+ }
+ }
+ ["inf"]=>
+ int(1)
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#6 (0) {
+ }
+ ["inf"]=>
+ int(2)
+ }
+ }
+}
+
diff --git a/ext/spl/tests/SplObjectStorage_var_dump.phpt b/ext/spl/tests/SplObjectStorage_var_dump.phpt
new file mode 100644
index 0000000..0439f46
--- /dev/null
+++ b/ext/spl/tests/SplObjectStorage_var_dump.phpt
@@ -0,0 +1,23 @@
+--TEST--
+SPL: SplObjectStorage: recursive var_dump
+--FILE--
+<?php
+$o = new SplObjectStorage();
+
+$o[new StdClass] = $o;
+
+var_dump($o);
+--EXPECTF--
+object(SplObjectStorage)#%d (1) {
+ ["storage":"SplObjectStorage":private]=>
+ array(1) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["inf"]=>
+ *RECURSION*
+ }
+ }
+}
diff --git a/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt b/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt
new file mode 100644
index 0000000..7dda782
--- /dev/null
+++ b/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Check that SplPriorityQueue::extract generate a warning and returns NULL when param passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$data_provider = array(
+ new stdClass,
+ array(),
+ true,
+ "string",
+ 12345,
+ 1.2345,
+ NULL
+);
+
+foreach($data_provider as $input) {
+
+ $h = new SplPriorityQueue();
+
+ var_dump($h->extract($input));
+}
+
+?>
+--EXPECTF--
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt b/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt
new file mode 100644
index 0000000..7d7b589
--- /dev/null
+++ b/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Check that SplPriorityQueue::insert generate a warning and returns NULL when rubbish params are passed
+--CREDITS--
+PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com)
+--FILE--
+<?php
+
+$h = new SplPriorityQueue();
+
+var_dump($h->insert(NULL));
+
+?>
+--EXPECTF--
+Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 1 given in %s on line %d
+NULL
+
diff --git a/ext/spl/tests/SplQueue_setIteratorMode.phpt b/ext/spl/tests/SplQueue_setIteratorMode.phpt
new file mode 100644
index 0000000..172a1d9
--- /dev/null
+++ b/ext/spl/tests/SplQueue_setIteratorMode.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplQueue can't be set to LIFO
+--CREDITS--
+Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009
+--FILE--
+<?php
+$queue = new SplQueue();
+try {
+ $queue->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECTF--
+Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen
diff --git a/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt b/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt
new file mode 100644
index 0000000..c3071f2
--- /dev/null
+++ b/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SplQueue setIteratorMode to LIFO produces fail condition in try/catch
+--CREDITS--
+PHPNW Test Fest 2009 - Jeremy Coates jeremy@phpnw.org.uk
+--FILE--
+<?php
+
+try {
+
+ $dll = new SplQueue();
+ $dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
+
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen
diff --git a/ext/spl/tests/SplStack_setIteratorMode.phpt b/ext/spl/tests/SplStack_setIteratorMode.phpt
new file mode 100644
index 0000000..d70105e
--- /dev/null
+++ b/ext/spl/tests/SplStack_setIteratorMode.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Check that SplStack can't be set to FIFO
+--CREDITS--
+Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009
+--FILE--
+<?php
+$stack = new SplStack();
+try {
+ $stack->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO);
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECTF--
+Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen
diff --git a/ext/spl/tests/SplTempFileObject_constructor_basic.phpt b/ext/spl/tests/SplTempFileObject_constructor_basic.phpt
new file mode 100644
index 0000000..b2e640c
--- /dev/null
+++ b/ext/spl/tests/SplTempFileObject_constructor_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL SplTempFileObject constructor sets correct defaults when pass 0 arguments
+--FILE--
+<?php
+var_dump(new SplTempFileObject());
+?>
+--EXPECTF--
+object(SplTempFileObject)#1 (5) {
+ ["pathName":"SplFileInfo":private]=>
+ string(10) "php://temp"
+ ["fileName":"SplFileInfo":private]=>
+ string(10) "php://temp"
+ ["openMode":"SplFileObject":private]=>
+ string(1) "w"
+ ["delimiter":"SplFileObject":private]=>
+ string(1) ","
+ ["enclosure":"SplFileObject":private]=>
+ string(1) """
+}
diff --git a/ext/spl/tests/SplTempFileObject_constructor_error.phpt b/ext/spl/tests/SplTempFileObject_constructor_error.phpt
new file mode 100644
index 0000000..d2717ac
--- /dev/null
+++ b/ext/spl/tests/SplTempFileObject_constructor_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL SplTempFileObject constructor sets correct defaults when pass 0 arguments
+--FILE--
+<?php
+new SplTempFileObject('invalid');
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'RuntimeException' with message 'SplTempFileObject::__construct() expects parameter 1 to be long, string given' in %s
+Stack trace:
+#0 %s: SplTempFileObject->__construct('invalid')
+#1 {main}
+ thrown in %s
diff --git a/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt b/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt
new file mode 100644
index 0000000..2ef1b2c
--- /dev/null
+++ b/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL SplTempFileObject constructor sets correct values when passed fixed memory size
+--FILE--
+<?php
+var_dump(new SplTempFileObject(1024));
+?>
+--EXPECTF--
+object(SplTempFileObject)#1 (5) {
+ ["pathName":"SplFileInfo":private]=>
+ string(25) "php://temp/maxmemory:1024"
+ ["fileName":"SplFileInfo":private]=>
+ string(25) "php://temp/maxmemory:1024"
+ ["openMode":"SplFileObject":private]=>
+ string(1) "w"
+ ["delimiter":"SplFileObject":private]=>
+ string(1) ","
+ ["enclosure":"SplFileObject":private]=>
+ string(1) """
+}
diff --git a/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt b/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt
new file mode 100644
index 0000000..9fe5892
--- /dev/null
+++ b/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL SplTempFileObject constructor sets correct defaults when passed a negative value
+--FILE--
+<?php
+var_dump(new SplTempFileObject(-1));
+?>
+--EXPECTF--
+object(SplTempFileObject)#1 (5) {
+ ["pathName":"SplFileInfo":private]=>
+ string(12) "php://memory"
+ ["fileName":"SplFileInfo":private]=>
+ string(12) "php://memory"
+ ["openMode":"SplFileObject":private]=>
+ string(1) "w"
+ ["delimiter":"SplFileObject":private]=>
+ string(1) ","
+ ["enclosure":"SplFileObject":private]=>
+ string(1) """
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic1.phpt b/ext/spl/tests/arrayObject___construct_basic1.phpt
new file mode 100644
index 0000000..f192cca
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic1.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: ArrayObject::__construct basic usage.
+--FILE--
+<?php
+echo "--> No arguments:\n";
+var_dump(new ArrayObject());
+
+echo "--> Object argument:\n";
+$a = new stdClass;
+$a->p = 'hello';
+var_dump(new ArrayObject($a));
+
+echo "--> Array argument:\n";
+var_dump(new ArrayObject(array('key1' => 'val1')));
+
+echo "--> Nested ArrayObject argument:\n";
+var_dump(new ArrayObject(new ArrayObject($a)));
+?>
+--EXPECTF--
+--> No arguments:
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+--> Object argument:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(stdClass)#1 (1) {
+ ["p"]=>
+ string(5) "hello"
+ }
+}
+--> Array argument:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["key1"]=>
+ string(4) "val1"
+ }
+}
+--> Nested ArrayObject argument:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(stdClass)#1 (1) {
+ ["p"]=>
+ string(5) "hello"
+ }
+ }
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic2.phpt b/ext/spl/tests/arrayObject___construct_basic2.phpt
new file mode 100644
index 0000000..bd27c42
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic2.phpt
@@ -0,0 +1,104 @@
+--TEST--
+SPL: ArrayObject::__construct basic usage.
+--FILE--
+<?php
+class C {
+ public $prop = 'C::prop.orig';
+}
+
+class MyArrayObject extends ArrayObject {
+ public $prop = 'MyArrayObject::prop.orig';
+}
+
+echo "--> Access prop on instance of ArrayObject:\n";
+$c = new C;
+$ao = new ArrayObject($c);
+testAccess($c, $ao);
+
+echo "\n--> Access prop on instance of MyArrayObject:\n";
+$c = new C;
+$ao = new MyArrayObject($c);
+testAccess($c, $ao);
+
+function testAccess($c, $ao) {
+ echo " - Iteration:\n";
+ foreach ($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+
+ echo " - Read:\n";
+ @var_dump($ao->prop, $ao['prop']);
+
+ echo " - Write:\n";
+ $ao->prop = 'changed1';
+ $ao['prop'] = 'changed2';
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - Isset:\n";
+ var_dump(isset($ao->prop), isset($ao['prop']));
+
+ echo " - Unset:\n";
+ unset($ao->prop);
+ unset($ao['prop']);
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - After:\n";
+ var_dump($ao, $c);
+}
+?>
+--EXPECTF--
+--> Access prop on instance of ArrayObject:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+NULL
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined property: ArrayObject::$prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (0) {
+ }
+}
+object(C)#1 (0) {
+}
+
+--> Access prop on instance of MyArrayObject:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(24) "MyArrayObject::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined property: MyArrayObject::$prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(MyArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#4 (0) {
+ }
+}
+object(C)#4 (0) {
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic3.phpt b/ext/spl/tests/arrayObject___construct_basic3.phpt
new file mode 100644
index 0000000..11a17a6
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic3.phpt
@@ -0,0 +1,104 @@
+--TEST--
+SPL: ArrayObject::__construct basic usage with ArrayObject::STD_PROP_LIST.
+--FILE--
+<?php
+class C {
+ public $prop = 'C::prop.orig';
+}
+
+class MyArrayObject extends ArrayObject {
+ public $prop = 'MyArrayObject::prop.orig';
+}
+
+echo "\n--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST:\n";
+$c = new C;
+$ao = new ArrayObject($c, ArrayObject::STD_PROP_LIST);
+testAccess($c, $ao);
+
+echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST:\n";
+$c = new C;
+$ao = new MyArrayObject($c, ArrayObject::STD_PROP_LIST);
+testAccess($c, $ao);
+
+function testAccess($c, $ao) {
+ echo " - Iteration:\n";
+ foreach ($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+
+ echo " - Read:\n";
+ @var_dump($ao->prop, $ao['prop']);
+
+ echo " - Write:\n";
+ $ao->prop = 'changed1';
+ $ao['prop'] = 'changed2';
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - Isset:\n";
+ var_dump(isset($ao->prop), isset($ao['prop']));
+
+ echo " - Unset:\n";
+ unset($ao->prop);
+ unset($ao['prop']);
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - After:\n";
+ var_dump($ao, $c);
+}
+?>
+--EXPECTF--
+--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+NULL
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined property: ArrayObject::$prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (0) {
+ }
+}
+object(C)#1 (0) {
+}
+
+--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(24) "MyArrayObject::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined property: MyArrayObject::$prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(MyArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#4 (0) {
+ }
+}
+object(C)#4 (0) {
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic4.phpt b/ext/spl/tests/arrayObject___construct_basic4.phpt
new file mode 100644
index 0000000..b0809de
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic4.phpt
@@ -0,0 +1,106 @@
+--TEST--
+SPL: ArrayObject::__construct basic usage with ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622.
+--FILE--
+<?php
+class C {
+ public $prop = 'C::prop.orig';
+}
+
+class MyArrayObject extends ArrayObject {
+ public $prop = 'MyArrayObject::prop.orig';
+}
+
+echo "\n--> Access prop on instance of ArrayObject with ArrayObject::ARRAY_AS_PROPS:\n";
+$c = new C;
+$ao = new ArrayObject($c, ArrayObject::ARRAY_AS_PROPS);
+testAccess($c, $ao);
+
+echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::ARRAY_AS_PROPS:\n";
+$c = new C;
+$ao = new MyArrayObject($c, ArrayObject::ARRAY_AS_PROPS);
+testAccess($c, $ao);
+
+function testAccess($c, $ao) {
+ echo " - Iteration:\n";
+ foreach ($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+
+ echo " - Read:\n";
+ @var_dump($ao->prop, $ao['prop']);
+
+ echo " - Write:\n";
+ $ao->prop = 'changed1';
+ $ao['prop'] = 'changed2';
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - Isset:\n";
+ var_dump(isset($ao->prop), isset($ao['prop']));
+
+ echo " - Unset:\n";
+ unset($ao->prop);
+ unset($ao['prop']);
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - After:\n";
+ var_dump($ao, $c);
+}
+?>
+--EXPECTF--
+--> Access prop on instance of ArrayObject with ArrayObject::ARRAY_AS_PROPS:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(12) "C::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed2"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined index: prop in %s on line 39
+
+Notice: Undefined index: prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (0) {
+ }
+}
+object(C)#1 (0) {
+}
+
+--> Access prop on instance of MyArrayObject with ArrayObject::ARRAY_AS_PROPS:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(24) "MyArrayObject::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined index: prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(MyArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#4 (0) {
+ }
+}
+object(C)#4 (0) {
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic5.phpt b/ext/spl/tests/arrayObject___construct_basic5.phpt
new file mode 100644
index 0000000..8c44ee2
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic5.phpt
@@ -0,0 +1,106 @@
+--TEST--
+SPL: ArrayObject::__construct basic usage with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622.
+--FILE--
+<?php
+class C {
+ public $prop = 'C::prop.orig';
+}
+
+class MyArrayObject extends ArrayObject {
+ public $prop = 'MyArrayObject::prop.orig';
+}
+
+echo "\n--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:\n";
+$c = new C;
+$ao = new ArrayObject($c, ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS);
+testAccess($c, $ao);
+
+echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:\n";
+$c = new C;
+$ao = new MyArrayObject($c, ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS);
+testAccess($c, $ao);
+
+function testAccess($c, $ao) {
+ echo " - Iteration:\n";
+ foreach ($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+
+ echo " - Read:\n";
+ @var_dump($ao->prop, $ao['prop']);
+
+ echo " - Write:\n";
+ $ao->prop = 'changed1';
+ $ao['prop'] = 'changed2';
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - Isset:\n";
+ var_dump(isset($ao->prop), isset($ao['prop']));
+
+ echo " - Unset:\n";
+ unset($ao->prop);
+ unset($ao['prop']);
+ var_dump($ao->prop, $ao['prop']);
+
+ echo " - After:\n";
+ var_dump($ao, $c);
+}
+?>
+--EXPECTF--
+--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(12) "C::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed2"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined index: prop in %s on line 39
+
+Notice: Undefined index: prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (0) {
+ }
+}
+object(C)#1 (0) {
+}
+
+--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:
+ - Iteration:
+ prop=>C::prop.orig
+ - Read:
+string(24) "MyArrayObject::prop.orig"
+string(12) "C::prop.orig"
+ - Write:
+string(8) "changed1"
+string(8) "changed2"
+ - Isset:
+bool(true)
+bool(true)
+ - Unset:
+
+Notice: Undefined index: prop in %s on line 40
+
+Notice: Undefined index: prop in %s on line 40
+NULL
+NULL
+ - After:
+object(MyArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#4 (0) {
+ }
+}
+object(C)#4 (0) {
+}
diff --git a/ext/spl/tests/arrayObject___construct_basic6.phpt b/ext/spl/tests/arrayObject___construct_basic6.phpt
new file mode 100644
index 0000000..1c7ec36
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_basic6.phpt
@@ -0,0 +1,80 @@
+--TEST--
+SPL: ArrayObject::__construct: check impact of ArrayObject::STD_PROP_LIST on var_dump.
+--FILE--
+<?php
+class MyArrayObject extends ArrayObject {
+ private $priv1 = 'secret1';
+ public $pub1 = 'public1';
+}
+
+$ao = new ArrayObject(array(1,2,3));
+$ao->p = 1;
+var_dump($ao);
+
+$ao = new ArrayObject(array(1,2,3), ArrayObject::STD_PROP_LIST);
+$ao->p = 1;
+var_dump($ao);
+
+$ao = new MyArrayObject(array(1,2,3));
+var_dump($ao);
+
+$ao = new MyArrayObject(array(1,2,3), ArrayObject::STD_PROP_LIST);
+var_dump($ao);
+?>
+--EXPECTF--
+object(ArrayObject)#1 (2) {
+ ["p"]=>
+ int(1)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+object(ArrayObject)#2 (2) {
+ ["p"]=>
+ int(1)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+object(MyArrayObject)#1 (3) {
+ ["priv1":"MyArrayObject":private]=>
+ string(7) "secret1"
+ ["pub1"]=>
+ string(7) "public1"
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+object(MyArrayObject)#2 (3) {
+ ["priv1":"MyArrayObject":private]=>
+ string(7) "secret1"
+ ["pub1"]=>
+ string(7) "public1"
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
diff --git a/ext/spl/tests/arrayObject___construct_error1.phpt b/ext/spl/tests/arrayObject___construct_error1.phpt
new file mode 100644
index 0000000..21c312d
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_error1.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: ArrayObject::__construct with bad iterator.
+--FILE--
+<?php
+echo "Bad iterator type:\n";
+$a = new stdClass;
+$a->p = 1;
+try {
+ var_dump(new ArrayObject($a, 0, "Exception"));
+} catch (InvalidArgumentException $e) {
+ echo $e->getMessage() . "(" . $e->getLine() . ")\n";
+}
+
+echo "Non-existent class:\n";
+try {
+ var_dump(new ArrayObject(new stdClass, 0, "nonExistentClassName"));
+} catch (InvalidArgumentException $e) {
+ echo $e->getMessage() . "(" . $e->getLine() . ")\n";
+}
+?>
+--EXPECTF--
+Bad iterator type:
+ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'Exception' given(6)
+Non-existent class:
+ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'nonExistentClassName' given(13)
diff --git a/ext/spl/tests/arrayObject___construct_error2.phpt b/ext/spl/tests/arrayObject___construct_error2.phpt
new file mode 100644
index 0000000..850a2cb
--- /dev/null
+++ b/ext/spl/tests/arrayObject___construct_error2.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: ArrayObject::__construct with too many arguments.
+--FILE--
+<?php
+echo "Too many arguments:\n";
+Class C implements Iterator {
+ function current() {}
+ function next() {}
+ function key() {}
+ function valid() {}
+ function rewind() {}
+}
+
+try {
+ var_dump(new ArrayObject(new stdClass, 0, "C", "extra"));
+} catch (InvalidArgumentException $e) {
+ echo $e->getMessage() . "(" . $e->getLine() . ")\n";
+}
+?>
+--EXPECTF--
+Too many arguments:
+ArrayObject::__construct() expects at most 3 parameters, 4 given(12) \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_asort_basic1.phpt b/ext/spl/tests/arrayObject_asort_basic1.phpt
new file mode 100644
index 0000000..53df1d5
--- /dev/null
+++ b/ext/spl/tests/arrayObject_asort_basic1.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::asort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype : int ArrayObject::asort()
+ * Description: proto int ArrayIterator::asort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::asort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump($ao1->asort());
+var_dump($ao1);
+var_dump($ao2->asort('blah'));
+var_dump($ao2);
+var_dump($ao2->asort(SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::asort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [0]=>
+ int(4)
+ }
+}
+
+Warning: asort() expects parameter 2 to be long, string given in %sarrayObject_asort_basic1.php on line %d
+bool(false)
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ ["a"]=>
+ int(4)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ }
+}
+bool(true)
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["a"]=>
+ int(4)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_asort_basic2.phpt b/ext/spl/tests/arrayObject_asort_basic2.phpt
new file mode 100644
index 0000000..d481d0c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_asort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::asort() function : basic functionality with object based store
+--FILE--
+<?php
+/* Prototype : int ArrayObject::asort()
+ * Description: proto int ArrayIterator::asort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::asort() : basic functionality ***\n";
+Class C {
+ public $prop1 = 'x';
+ public $prop2 = 'z';
+ private $prop3 = 'a';
+ public $prop4 = 'x';
+}
+
+$c = new C;
+$ao1 = new ArrayObject($c);
+var_dump($ao1->asort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::asort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["prop3":"C":private]=>
+ string(1) "a"
+ ["prop1"]=>
+ string(1) "x"
+ ["prop4"]=>
+ string(1) "x"
+ ["prop2"]=>
+ string(1) "z"
+ }
+}
+object(C)#1 (4) {
+ ["prop3":"C":private]=>
+ string(1) "a"
+ ["prop1"]=>
+ string(1) "x"
+ ["prop4"]=>
+ string(1) "x"
+ ["prop2"]=>
+ string(1) "z"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_clone_basic1.phpt b/ext/spl/tests/arrayObject_clone_basic1.phpt
new file mode 100644
index 0000000..dd4abf3
--- /dev/null
+++ b/ext/spl/tests/arrayObject_clone_basic1.phpt
@@ -0,0 +1,48 @@
+--TEST--
+SPL: Cloning an instance of ArrayObject which wraps an array.
+--FILE--
+<?php
+$a = array(1,2);
+$aa1 = new ArrayObject($a);
+$a['p1'] = 'new element added to a before clone';
+
+$aa2 = clone $aa1;
+
+$a['p2'] = 'new element added to a after clone';
+$aa1['new.aa1'] = 'new element added to aa1';
+$aa2['new.aa2'] = 'new element added to aa2';
+var_dump($a, $aa1, $aa2);
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ ["p1"]=>
+ string(35) "new element added to a before clone"
+ ["p2"]=>
+ string(34) "new element added to a after clone"
+}
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ ["new.aa1"]=>
+ string(24) "new element added to aa1"
+ }
+}
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ ["new.aa2"]=>
+ string(24) "new element added to aa2"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_clone_basic2.phpt b/ext/spl/tests/arrayObject_clone_basic2.phpt
new file mode 100644
index 0000000..932eaed
--- /dev/null
+++ b/ext/spl/tests/arrayObject_clone_basic2.phpt
@@ -0,0 +1,46 @@
+--TEST--
+SPL: Cloning an instance of ArrayObject which wraps an object.
+--FILE--
+<?php
+class C { }
+
+$c = new C;
+$ao1 = new ArrayObject($c);
+$c->p1 = 'new prop added to c before clone';
+
+$ao2 = clone $ao1;
+
+$c->p2 = 'new prop added to c after clone';
+$ao1['new.ao1'] = 'new element added to ao1';
+$ao2['new.ao2'] = 'new element added to ao2';
+var_dump($c, $ao1, $ao2);
+?>
+--EXPECTF--
+object(C)#1 (3) {
+ ["p1"]=>
+ string(32) "new prop added to c before clone"
+ ["p2"]=>
+ string(31) "new prop added to c after clone"
+ ["new.ao1"]=>
+ string(24) "new element added to ao1"
+}
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (3) {
+ ["p1"]=>
+ string(32) "new prop added to c before clone"
+ ["p2"]=>
+ string(31) "new prop added to c after clone"
+ ["new.ao1"]=>
+ string(24) "new element added to ao1"
+ }
+}
+object(ArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(2) {
+ ["p1"]=>
+ string(32) "new prop added to c before clone"
+ ["new.ao2"]=>
+ string(24) "new element added to ao2"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_clone_basic3.phpt b/ext/spl/tests/arrayObject_clone_basic3.phpt
new file mode 100644
index 0000000..f7ac894
--- /dev/null
+++ b/ext/spl/tests/arrayObject_clone_basic3.phpt
@@ -0,0 +1,80 @@
+--TEST--
+SPL: Cloning nested ArrayObjects.
+--FILE--
+<?php
+class C {
+ public $p = 'C::p.orig';
+}
+
+$wrappedObject = new C;
+$innerArrayObject = new ArrayObject($wrappedObject);
+
+$outerArrayObject = new ArrayObject($innerArrayObject);
+
+$wrappedObject->dynamic1 = 'new prop added to $wrappedObject before clone';
+$clonedOuterArrayObject = clone $outerArrayObject;
+$wrappedObject->dynamic2 = 'new prop added to $wrappedObject after clone';
+
+$innerArrayObject['new.iAO'] = 'new element added $innerArrayObject';
+$outerArrayObject['new.oAO'] = 'new element added to $outerArrayObject';
+$clonedOuterArrayObject['new.coAO'] = 'new element added to $clonedOuterArrayObject';
+
+var_dump($wrappedObject, $innerArrayObject, $outerArrayObject, $clonedOuterArrayObject);
+?>
+--EXPECTF--
+object(C)#1 (5) {
+ ["p"]=>
+ string(9) "C::p.orig"
+ ["dynamic1"]=>
+ string(45) "new prop added to $wrappedObject before clone"
+ ["dynamic2"]=>
+ string(44) "new prop added to $wrappedObject after clone"
+ ["new.iAO"]=>
+ string(35) "new element added $innerArrayObject"
+ ["new.oAO"]=>
+ string(38) "new element added to $outerArrayObject"
+}
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["p"]=>
+ string(9) "C::p.orig"
+ ["dynamic1"]=>
+ string(45) "new prop added to $wrappedObject before clone"
+ ["dynamic2"]=>
+ string(44) "new prop added to $wrappedObject after clone"
+ ["new.iAO"]=>
+ string(35) "new element added $innerArrayObject"
+ ["new.oAO"]=>
+ string(38) "new element added to $outerArrayObject"
+ }
+}
+object(ArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["p"]=>
+ string(9) "C::p.orig"
+ ["dynamic1"]=>
+ string(45) "new prop added to $wrappedObject before clone"
+ ["dynamic2"]=>
+ string(44) "new prop added to $wrappedObject after clone"
+ ["new.iAO"]=>
+ string(35) "new element added $innerArrayObject"
+ ["new.oAO"]=>
+ string(38) "new element added to $outerArrayObject"
+ }
+ }
+}
+object(ArrayObject)#4 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ ["p"]=>
+ string(9) "C::p.orig"
+ ["dynamic1"]=>
+ string(45) "new prop added to $wrappedObject before clone"
+ ["new.coAO"]=>
+ string(44) "new element added to $clonedOuterArrayObject"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_count_basic1.phpt b/ext/spl/tests/arrayObject_count_basic1.phpt
new file mode 100644
index 0000000..a003c2c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_count_basic1.phpt
@@ -0,0 +1,84 @@
+--TEST--
+SPL: ArrayObject::count() and ArrayIterator::count() basic functionality.
+--FILE--
+==ArrayObject==
+<?php
+class C extends ArrayObject {
+ function count() {
+ return 99;
+ }
+}
+
+$c = new C;
+$ao = new ArrayObject;
+
+var_dump(count($c), count($ao));
+
+$c[] = 'a';
+$ao[] = 'a';
+var_dump(count($c), count($ao));
+
+$c[] = 'b';
+$ao[] = 'b';
+var_dump(count($c), count($ao));
+
+unset($c[0]);
+unset($ao[0]);
+var_dump($c->count(), $ao->count());
+
+//Extra args are ignored.
+var_dump($ao->count('blah'));
+?>
+==ArrayIterator==
+<?php
+class D extends ArrayIterator {
+ function count() {
+ return 99;
+ }
+}
+
+$c = new D;
+$ao = new ArrayIterator;
+
+var_dump(count($c), count($ao));
+
+$c[] = 'a';
+$ao[] = 'a';
+var_dump(count($c), count($ao));
+
+$c[] = 'b';
+$ao[] = 'b';
+var_dump(count($c), count($ao));
+
+unset($c[0]);
+unset($ao[0]);
+var_dump($c->count(), $ao->count());
+
+//Extra args are ignored.
+var_dump($ao->count('blah'));
+?>
+--EXPECTF--
+==ArrayObject==
+int(99)
+int(0)
+int(99)
+int(1)
+int(99)
+int(2)
+int(99)
+int(1)
+
+Warning: ArrayObject::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+==ArrayIterator==
+int(99)
+int(0)
+int(99)
+int(1)
+int(99)
+int(2)
+int(99)
+int(1)
+
+Warning: ArrayIterator::count() expects exactly 0 parameters, 1 given in %s on line %d
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt
new file mode 100644
index 0000000..988f103
--- /dev/null
+++ b/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt
@@ -0,0 +1,40 @@
+--TEST--
+SPL: ArrayObject::exchangeArray() and copy-on-write references
+--FILE--
+<?php
+$ao = new ArrayObject();
+$swapIn = array();
+$cowRef = $swapIn; // create a copy-on-write ref to $swapIn
+$ao->exchangeArray($swapIn);
+
+$ao['a'] = 'adding element to $ao';
+$swapIn['b'] = 'adding element to $swapIn';
+$ao['c'] = 'adding another element to $ao';
+
+echo "\n--> swapIn: ";
+var_dump($swapIn);
+
+echo "\n--> cowRef: ";
+var_dump($cowRef);
+
+echo "\n--> ao: ";
+var_dump($ao);
+?>
+--EXPECTF--
+--> swapIn: array(1) {
+ ["b"]=>
+ string(25) "adding element to $swapIn"
+}
+
+--> cowRef: array(0) {
+}
+
+--> ao: object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(2) {
+ ["a"]=>
+ string(21) "adding element to $ao"
+ ["c"]=>
+ string(29) "adding another element to $ao"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt
new file mode 100644
index 0000000..c7f1b3a
--- /dev/null
+++ b/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt
@@ -0,0 +1,97 @@
+--TEST--
+SPL: ArrayObject::exchangeArray() with various object arguments
+--FILE--
+<?php
+echo "--> exchangeArray(array):\n";
+$ao = new ArrayObject();
+$ao->exchangeArray(array('key'=>'original'));
+var_dump($ao['key']);
+var_dump($ao);
+
+echo "\n--> exchangeArray(normal object):\n";
+$obj = new stdClass;
+$obj->key = 'normal object prop';
+$ao->exchangeArray($obj);
+var_dump($ao['key']);
+var_dump($ao);
+
+echo "\n--> exchangeArray(ArrayObject):\n";
+$obj = new ArrayObject(array('key'=>'ArrayObject element'));
+$ao->exchangeArray($obj);
+var_dump($ao['key']);
+var_dump($ao);
+
+echo "\n--> exchangeArray(ArrayIterator):\n";
+$obj = new ArrayIterator(array('key'=>'ArrayIterator element'));
+$ao->exchangeArray($obj);
+var_dump($ao['key']);
+var_dump($ao);
+
+echo "\n--> exchangeArray(nested ArrayObject):\n";
+$obj = new ArrayObject(new ArrayObject(array('key'=>'nested ArrayObject element')));
+$ao->exchangeArray($obj);
+var_dump($ao['key']);
+var_dump($ao);
+?>
+--EXPECTF--
+--> exchangeArray(array):
+string(8) "original"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["key"]=>
+ string(8) "original"
+ }
+}
+
+--> exchangeArray(normal object):
+string(18) "normal object prop"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(stdClass)#%d (1) {
+ ["key"]=>
+ string(18) "normal object prop"
+ }
+}
+
+--> exchangeArray(ArrayObject):
+string(19) "ArrayObject element"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["key"]=>
+ string(19) "ArrayObject element"
+ }
+ }
+}
+
+--> exchangeArray(ArrayIterator):
+string(21) "ArrayIterator element"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(1) {
+ ["key"]=>
+ string(21) "ArrayIterator element"
+ }
+ }
+}
+
+--> exchangeArray(nested ArrayObject):
+string(26) "nested ArrayObject element"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["key"]=>
+ string(26) "nested ArrayObject element"
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt
new file mode 100644
index 0000000..4045b7a
--- /dev/null
+++ b/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt
@@ -0,0 +1,128 @@
+--TEST--
+SPL: ArrayObject::exchangeArray() basic usage with object as underlying data store.
+--FILE--
+<?php
+
+class C {
+ public $pub1 = 'public1';
+}
+
+echo "--> exchangeArray() with objects:\n";
+$original = new C;
+$ao = new ArrayObject($original);
+$swapIn = new C;
+try {
+ $copy = $ao->exchangeArray($swapIn);
+ $copy['addedToCopy'] = 'added To Copy';
+} catch (Exception $e) {
+ echo "Exception:" . $e->getMessage() . "\n";
+}
+$swapIn->addedToSwapIn = 'added To Swap-In';
+$original->addedToOriginal = 'added To Original';
+var_dump($ao, $original, $swapIn, $copy);
+
+
+echo "\n\n--> exchangeArray() with no arg:\n";
+unset($original, $ao, $swapIn, $copy);
+$original = new C;
+$ao = new ArrayObject($original);
+try {
+ $copy = $ao->exchangeArray();
+ $copy['addedToCopy'] = 'added To Copy';
+} catch (Exception $e) {
+ echo "Exception:" . $e->getMessage() . "\n";
+}
+$original->addedToOriginal = 'added To Original';
+var_dump($ao, $original, $copy);
+
+echo "\n\n--> exchangeArray() with bad arg type:\n";
+unset($original, $ao, $swapIn, $copy);
+$original = new C;
+$ao = new ArrayObject($original);
+try {
+ $copy = $ao->exchangeArray(null);
+ $copy['addedToCopy'] = 'added To Copy';
+} catch (Exception $e) {
+ echo "Exception:" . $e->getMessage() . "\n";
+}
+$original->addedToOriginal = 'added To Original';
+var_dump($ao, $original, $copy);
+
+?>
+--EXPECTF--
+--> exchangeArray() with objects:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#3 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToSwapIn"]=>
+ string(16) "added To Swap-In"
+ }
+}
+object(C)#1 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToOriginal"]=>
+ string(17) "added To Original"
+}
+object(C)#3 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToSwapIn"]=>
+ string(16) "added To Swap-In"
+}
+array(2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToCopy"]=>
+ string(13) "added To Copy"
+}
+
+
+--> exchangeArray() with no arg:
+
+Warning: ArrayObject::exchangeArray() expects exactly 1 parameter, 0 given in %s on line 27
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#3 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToOriginal"]=>
+ string(17) "added To Original"
+ }
+}
+object(C)#3 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToOriginal"]=>
+ string(17) "added To Original"
+}
+array(2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToCopy"]=>
+ string(13) "added To Copy"
+}
+
+
+--> exchangeArray() with bad arg type:
+Exception:Passed variable is not an array or object, using empty array instead
+
+Notice: Undefined variable: copy in %s on line 46
+object(ArrayObject)#3 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#2 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToOriginal"]=>
+ string(17) "added To Original"
+ }
+}
+object(C)#2 (2) {
+ ["pub1"]=>
+ string(7) "public1"
+ ["addedToOriginal"]=>
+ string(17) "added To Original"
+}
+NULL
diff --git a/ext/spl/tests/arrayObject_getFlags_basic1.phpt b/ext/spl/tests/arrayObject_getFlags_basic1.phpt
new file mode 100644
index 0000000..b078c51
--- /dev/null
+++ b/ext/spl/tests/arrayObject_getFlags_basic1.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: ArrayObject::getFlags() basic usage
+--FILE--
+<?php
+$ao = new ArrayObject(new ArrayObject(new stdClass));
+var_dump($ao->getFlags());
+
+$ao = new ArrayObject(new ArrayObject(array(1,2,3)), ArrayObject::STD_PROP_LIST);
+var_dump($ao->getFlags());
+
+$ao = new ArrayObject(new ArrayIterator(new ArrayObject()), ArrayObject::ARRAY_AS_PROPS);
+var_dump($ao->getFlags());
+
+$ao = new ArrayObject(new ArrayObject(), ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS);
+var_dump($ao->getFlags());
+
+$cao = clone $ao;
+var_dump($cao->getFlags());
+?>
+--EXPECTF--
+int(0)
+int(1)
+int(2)
+int(3)
+int(3) \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_getFlags_basic2.phpt b/ext/spl/tests/arrayObject_getFlags_basic2.phpt
new file mode 100644
index 0000000..f7d56ea
--- /dev/null
+++ b/ext/spl/tests/arrayObject_getFlags_basic2.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: ArrayObject::getFlags() - ensure flags are passed on to nested array objects and iterators.
+--FILE--
+<?php
+$ao = new ArrayObject(array(), ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS);
+var_dump($ao->getFlags());
+
+$ao2 = new ArrayObject($ao);
+var_dump($ao2->getFlags());
+var_dump($ao2->getIterator()->getFlags());
+
+$ai = new ArrayIterator($ao);
+var_dump($ai->getFlags());
+
+$ao2 = new ArrayObject($ao, 0);
+var_dump($ao2->getFlags());
+
+?>
+--EXPECTF--
+int(3)
+int(3)
+int(3)
+int(3)
+int(0) \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt b/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt
new file mode 100644
index 0000000..b23c196
--- /dev/null
+++ b/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt
@@ -0,0 +1,116 @@
+--TEST--
+SPL: ArrayObject::getIteratorClass and ArrayObject::setIteratorClass basic functionality
+--FILE--
+<?php
+class MyIterator extends ArrayIterator {
+
+ function __construct() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+ function rewind() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ return parent::rewind();
+ }
+
+ function valid() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ return parent::valid();
+ }
+
+ function current() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ return parent::current();
+ }
+
+ function next() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ return parent::next();
+ }
+
+ function key() {
+ $args = func_get_args();
+ echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ return parent::key();
+ }
+}
+
+$ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "MyIterator");
+
+echo "--> Access using MyIterator:\n";
+var_dump($ao->getIteratorClass());
+var_dump($ao->getIterator());
+foreach($ao as $key=>$value) {
+ echo " $key=>$value\n";
+}
+
+echo "\n\n--> Access using ArrayIterator:\n";
+var_dump($ao->setIteratorClass("ArrayIterator"));
+var_dump($ao->getIteratorClass());
+var_dump($ao->getIterator());
+foreach($ao as $key=>$value) {
+ echo "$key=>$value\n";
+}
+
+?>
+--EXPECTF--
+--> Access using MyIterator:
+string(10) "MyIterator"
+object(MyIterator)#2 (1) {
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ }
+ }
+}
+ In MyIterator::rewind()
+ In MyIterator::valid()
+ In MyIterator::current()
+ In MyIterator::key()
+ a=>1
+ In MyIterator::next()
+ In MyIterator::valid()
+ In MyIterator::current()
+ In MyIterator::key()
+ b=>2
+ In MyIterator::next()
+ In MyIterator::valid()
+ In MyIterator::current()
+ In MyIterator::key()
+ c=>3
+ In MyIterator::next()
+ In MyIterator::valid()
+
+
+--> Access using ArrayIterator:
+NULL
+string(13) "ArrayIterator"
+object(ArrayIterator)#3 (1) {
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ }
+ }
+}
+a=>1
+b=>2
+c=>3
diff --git a/ext/spl/tests/arrayObject_ksort_basic1.phpt b/ext/spl/tests/arrayObject_ksort_basic1.phpt
new file mode 100644
index 0000000..8f37938
--- /dev/null
+++ b/ext/spl/tests/arrayObject_ksort_basic1.phpt
@@ -0,0 +1,67 @@
+--TEST--
+SPL: Test ArrayObject::ksort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype : int ArrayObject::ksort()
+ * Description: proto int ArrayIterator::ksort()
+ * Sort the entries by key.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::ksort() : basic functionality ***\n";
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('b'=>4,'a'=>2,'q'=>3, 99=>'x'));
+var_dump($ao1->ksort());
+var_dump($ao1);
+var_dump($ao2->ksort('blah'));
+var_dump($ao2);
+var_dump($ao2->ksort(SORT_STRING));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::ksort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+
+Warning: ksort() expects parameter 2 to be long, string given in %sarrayObject_ksort_basic1.php on line %d
+bool(false)
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(4) {
+ ["b"]=>
+ int(4)
+ ["a"]=>
+ int(2)
+ ["q"]=>
+ int(3)
+ [99]=>
+ string(1) "x"
+ }
+}
+bool(true)
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(4) {
+ [99]=>
+ string(1) "x"
+ ["a"]=>
+ int(2)
+ ["b"]=>
+ int(4)
+ ["q"]=>
+ int(3)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_ksort_basic2.phpt b/ext/spl/tests/arrayObject_ksort_basic2.phpt
new file mode 100644
index 0000000..1464e73
--- /dev/null
+++ b/ext/spl/tests/arrayObject_ksort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::ksort() function : basic functionality with object base store
+--FILE--
+<?php
+/* Prototype : int ArrayObject::ksort()
+ * Description: proto int ArrayIterator::ksort()
+ * Sort the entries by key.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::ksort() : basic functionality ***\n";
+Class C {
+ public $x = 'prop1';
+ public $z = 'prop2';
+ public $a = 'prop3';
+ private $b = 'prop4';
+}
+
+$c = new C;
+$ao1 = new ArrayObject($c);
+var_dump($ao1->ksort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::ksort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["b":"C":private]=>
+ string(5) "prop4"
+ ["a"]=>
+ string(5) "prop3"
+ ["x"]=>
+ string(5) "prop1"
+ ["z"]=>
+ string(5) "prop2"
+ }
+}
+object(C)#1 (4) {
+ ["b":"C":private]=>
+ string(5) "prop4"
+ ["a"]=>
+ string(5) "prop3"
+ ["x"]=>
+ string(5) "prop1"
+ ["z"]=>
+ string(5) "prop2"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_magicMethods1.phpt b/ext/spl/tests/arrayObject_magicMethods1.phpt
new file mode 100644
index 0000000..ec4812f
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods1.phpt
@@ -0,0 +1,195 @@
+--TEST--
+SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using [].
+--FILE--
+<?php
+class UsesMagic {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+
+$obj = new UsesMagic;
+
+$ao = new ArrayObject($obj);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao['a'] = 'changed';
+$ao['dynamic'] = 'new';
+$ao['dynamic'] = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao['a']);
+var_dump($ao['nonexistent']);
+var_dump($ao['dynamic']);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao['a']));
+var_dump(isset($ao['nonexistent']));
+var_dump(isset($ao['dynamic']));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao['a']);
+unset($ao['nonexistent']);
+unset($ao['dynamic']);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+string(7) "changed"
+
+Notice: Undefined index: nonexistent in %s on line 42
+NULL
+string(11) "new.changed"
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+bool(true)
+bool(false)
+bool(true)
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+
+Notice: Undefined index: nonexistent in %s on line 60
+ Original wrapped object:
+object(UsesMagic)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_magicMethods2.phpt b/ext/spl/tests/arrayObject_magicMethods2.phpt
new file mode 100644
index 0000000..691a9a1
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods2.phpt
@@ -0,0 +1,197 @@
+--TEST--
+SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using ->.
+--FILE--
+<?php
+class UsesMagic {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+
+$obj = new UsesMagic;
+
+$ao = new ArrayObject($obj);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao->a = 'changed';
+$ao->dynamic = 'new';
+$ao->dynamic = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao->a);
+var_dump($ao->nonexistent);
+var_dump($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao->a));
+var_dump(isset($ao->nonexistent));
+var_dump(isset($ao->dynamic));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao->a);
+unset($ao->nonexistent);
+unset($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+ Original wrapped object:
+object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (3) {
+ ["a"]=>
+ string(7) "changed"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+string(7) "changed"
+
+Notice: Undefined property: ArrayObject::$nonexistent in %s on line 42
+NULL
+string(11) "new.changed"
+ Original wrapped object:
+object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (3) {
+ ["a"]=>
+ string(7) "changed"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+bool(true)
+bool(false)
+bool(true)
+ Original wrapped object:
+object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (3) {
+ ["a"]=>
+ string(7) "changed"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+ Original wrapped object:
+object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_magicMethods3.phpt b/ext/spl/tests/arrayObject_magicMethods3.phpt
new file mode 100644
index 0000000..6231cea
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods3.phpt
@@ -0,0 +1,195 @@
+--TEST--
+SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using -> and ArrayObject::ARRAY_AS_PROPS.
+--FILE--
+<?php
+class UsesMagic {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+
+$obj = new UsesMagic;
+
+$ao = new ArrayObject($obj, ArrayObject::ARRAY_AS_PROPS);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao->a = 'changed';
+$ao->dynamic = 'new';
+$ao->dynamic = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao->a);
+var_dump($ao->nonexistent);
+var_dump($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao->a));
+var_dump(isset($ao->nonexistent));
+var_dump(isset($ao->dynamic));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao->a);
+unset($ao->nonexistent);
+unset($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+string(7) "changed"
+
+Notice: Undefined index: nonexistent in %s on line 42
+NULL
+string(11) "new.changed"
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+bool(true)
+bool(false)
+bool(true)
+ Original wrapped object:
+object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+
+Notice: Undefined index: nonexistent in %s on line 60
+ Original wrapped object:
+object(UsesMagic)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ object(UsesMagic)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"UsesMagic":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_magicMethods4.phpt b/ext/spl/tests/arrayObject_magicMethods4.phpt
new file mode 100644
index 0000000..9580dc5
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods4.phpt
@@ -0,0 +1,206 @@
+--TEST--
+SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject are not invoked when manipulating its elements using [].
+--FILE--
+<?php
+class C {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+}
+
+class UsesMagic extends ArrayObject {
+
+ public $b = "This should not be in the storage";
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+$obj = new C;
+$ao = new UsesMagic($obj);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao['a'] = 'changed';
+$ao['dynamic'] = 'new';
+$ao['dynamic'] = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao['a']);
+var_dump($ao['nonexistent']);
+var_dump($ao['dynamic']);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao['a']));
+var_dump(isset($ao['nonexistent']));
+var_dump(isset($ao['dynamic']));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao['a']);
+unset($ao['nonexistent']);
+unset($ao['dynamic']);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(33) "This should not be in the storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+string(7) "changed"
+
+Notice: Undefined index: nonexistent in %s on line 45
+NULL
+string(11) "new.changed"
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(33) "This should not be in the storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+bool(true)
+bool(false)
+bool(true)
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(33) "This should not be in the storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+
+Notice: Undefined index: nonexistent in %s on line 63
+ Original wrapped object:
+object(C)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(33) "This should not be in the storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_magicMethods5.phpt b/ext/spl/tests/arrayObject_magicMethods5.phpt
new file mode 100644
index 0000000..023086d
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods5.phpt
@@ -0,0 +1,206 @@
+--TEST--
+SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject ARE invoked when manipulating its elements using ->.
+--FILE--
+<?php
+class C {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+}
+
+class UsesMagic extends ArrayObject {
+
+ public $b = "This should appear in storage";
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+$obj = new C;
+$ao = new UsesMagic($obj);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao->a = 'changed';
+$ao->dynamic = 'new';
+$ao->dynamic = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao->a);
+var_dump($ao->nonexistent);
+var_dump($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao->a));
+var_dump(isset($ao->nonexistent));
+var_dump(isset($ao->dynamic));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao->a);
+unset($ao->nonexistent);
+unset($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+In UsesMagic::__set(a,changed)
+In UsesMagic::__set(dynamic,new)
+In UsesMagic::__set(dynamic,new.changed)
+ Original wrapped object:
+object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(29) "This should appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+In UsesMagic::__get(a)
+NULL
+In UsesMagic::__get(nonexistent)
+NULL
+In UsesMagic::__get(dynamic)
+NULL
+ Original wrapped object:
+object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(29) "This should appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+In UsesMagic::__isset(a)
+bool(false)
+In UsesMagic::__isset(nonexistent)
+bool(false)
+In UsesMagic::__isset(dynamic)
+bool(false)
+ Original wrapped object:
+object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(29) "This should appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+In UsesMagic::__unset(a)
+In UsesMagic::__unset(nonexistent)
+In UsesMagic::__unset(dynamic)
+ Original wrapped object:
+object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(29) "This should appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_magicMethods6.phpt b/ext/spl/tests/arrayObject_magicMethods6.phpt
new file mode 100644
index 0000000..b43f56c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_magicMethods6.phpt
@@ -0,0 +1,206 @@
+--TEST--
+SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject are not invoked when manipulating its elements using -> ArrayObject::ARRAY_AS_PROPS.
+--FILE--
+<?php
+class C {
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+
+ private $priv = 'secret';
+}
+
+class UsesMagic extends ArrayObject {
+
+ public $b = "This should never appear in storage";
+
+ function __get($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __set($name, $value) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __isset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+ function __unset($name) {
+ $args = func_get_args();
+ echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n";
+ }
+
+}
+$obj = new C;
+$ao = new UsesMagic($obj, ArrayObject::ARRAY_AS_PROPS);
+echo "\n--> Write existent, non-existent and dynamic:\n";
+$ao->a = 'changed';
+$ao->dynamic = 'new';
+$ao->dynamic = 'new.changed';
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Read existent, non-existent and dynamic:\n";
+var_dump($ao->a);
+var_dump($ao->nonexistent);
+var_dump($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> isset existent, non-existent and dynamic:\n";
+var_dump(isset($ao->a));
+var_dump(isset($ao->nonexistent));
+var_dump(isset($ao->dynamic));
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+
+echo "\n--> Unset existent, non-existent and dynamic:\n";
+unset($ao->a);
+unset($ao->nonexistent);
+unset($ao->dynamic);
+echo " Original wrapped object:\n";
+var_dump($obj);
+echo " Wrapping ArrayObject:\n";
+var_dump($ao);
+?>
+--EXPECTF--
+--> Write existent, non-existent and dynamic:
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(35) "This should never appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Read existent, non-existent and dynamic:
+string(7) "changed"
+
+Notice: Undefined index: nonexistent in %s on line 45
+NULL
+string(11) "new.changed"
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(35) "This should never appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> isset existent, non-existent and dynamic:
+bool(true)
+bool(false)
+bool(true)
+ Original wrapped object:
+object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(35) "This should never appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (5) {
+ ["a"]=>
+ string(7) "changed"
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ ["dynamic"]=>
+ string(11) "new.changed"
+ }
+}
+
+--> Unset existent, non-existent and dynamic:
+
+Notice: Undefined index: nonexistent in %s on line 63
+ Original wrapped object:
+object(C)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+}
+ Wrapping ArrayObject:
+object(UsesMagic)#2 (2) {
+ ["b"]=>
+ string(35) "This should never appear in storage"
+ ["storage":"ArrayObject":private]=>
+ object(C)#1 (3) {
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["priv":"C":private]=>
+ string(6) "secret"
+ }
+}
diff --git a/ext/spl/tests/arrayObject_natcasesort_basic1.phpt b/ext/spl/tests/arrayObject_natcasesort_basic1.phpt
new file mode 100644
index 0000000..62ad2ed
--- /dev/null
+++ b/ext/spl/tests/arrayObject_natcasesort_basic1.phpt
@@ -0,0 +1,56 @@
+--TEST--
+SPL: Test ArrayObject::natcasesort() function : basic functionality
+--FILE--
+<?php
+/* Prototype : int ArrayObject::natcasesort()
+ * Description: proto int ArrayIterator::natcasesort()
+ Sort the entries by values using case insensitive "natural order" algorithm.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::natcasesort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array('boo10','boo1','boo2','boo22','BOO5'));
+$ao2 = new ArrayObject(array('a'=>'boo10','b'=>'boo1','c'=>'boo2','d'=>'boo22','e'=>'BOO5'));
+var_dump($ao1->natcasesort());
+var_dump($ao1);
+var_dump($ao2->natcasesort('blah'));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::natcasesort() : basic functionality ***
+bool(true)
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ [1]=>
+ string(4) "boo1"
+ [2]=>
+ string(4) "boo2"
+ [4]=>
+ string(4) "BOO5"
+ [0]=>
+ string(5) "boo10"
+ [3]=>
+ string(5) "boo22"
+ }
+}
+bool(true)
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ ["b"]=>
+ string(4) "boo1"
+ ["c"]=>
+ string(4) "boo2"
+ ["e"]=>
+ string(4) "BOO5"
+ ["a"]=>
+ string(5) "boo10"
+ ["d"]=>
+ string(5) "boo22"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_natsort_basic1.phpt b/ext/spl/tests/arrayObject_natsort_basic1.phpt
new file mode 100644
index 0000000..1b4fd60
--- /dev/null
+++ b/ext/spl/tests/arrayObject_natsort_basic1.phpt
@@ -0,0 +1,57 @@
+--TEST--
+SPL: Test ArrayObject::natsort() function : basic functionality
+--FILE--
+<?php
+/* Prototype : int ArrayObject::natsort()
+ * Description: proto int ArrayIterator::natsort()
+ Sort the entries by values using "natural order" algorithm.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::natsort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array('boo10','boo1','boo2','boo22','BOO5'));
+$ao2 = new ArrayObject(array('a'=>'boo10','b'=>'boo1','c'=>'boo2','d'=>'boo22','e'=>'BOO5'));
+var_dump($ao1->natsort());
+var_dump($ao1);
+var_dump($ao2->natsort('blah'));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::natsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ [4]=>
+ string(4) "BOO5"
+ [1]=>
+ string(4) "boo1"
+ [2]=>
+ string(4) "boo2"
+ [0]=>
+ string(5) "boo10"
+ [3]=>
+ string(5) "boo22"
+ }
+}
+bool(true)
+object(ArrayObject)#2 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ ["e"]=>
+ string(4) "BOO5"
+ ["b"]=>
+ string(4) "boo1"
+ ["c"]=>
+ string(4) "boo2"
+ ["a"]=>
+ string(5) "boo10"
+ ["d"]=>
+ string(5) "boo22"
+ }
+}
+===DONE===
+
diff --git a/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt b/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt
new file mode 100644
index 0000000..1953643
--- /dev/null
+++ b/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt
@@ -0,0 +1,10 @@
+--TEST--
+SPL: ArrayObject::offsetExists() should return true for element containing NULL
+--FILE--
+<?php
+$ao = new ArrayObject(array('foo' => null));
+var_dump($ao->offsetExists('foo'));
+
+?>
+--EXPECTF--
+bool(true) \ No newline at end of file
diff --git a/ext/spl/tests/arrayObject_setFlags_basic1.phpt b/ext/spl/tests/arrayObject_setFlags_basic1.phpt
new file mode 100644
index 0000000..391b0ee
--- /dev/null
+++ b/ext/spl/tests/arrayObject_setFlags_basic1.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: ArrayObject::setFlags basic usage with ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622.
+--FILE--
+<?php
+class C extends ArrayObject {
+ public $p = 'object property';
+}
+
+function access_p($ao) {
+ // isset
+ var_dump(isset($ao->p));
+ // read
+ var_dump($ao->p);
+ // write
+ $ao->p = $ao->p . '.changed';
+ var_dump($ao->p);
+}
+
+$ao = new C(array('p'=>'array element'));
+$ao->setFlags(ArrayObject::ARRAY_AS_PROPS);
+
+echo "\n--> Access the real property:\n";
+access_p($ao);
+
+echo "\n--> Remove the real property and access the array element:\n";
+unset($ao->p);
+access_p($ao);
+
+echo "\n--> Remove the array element and try access again:\n";
+unset($ao->p);
+access_p($ao);
+?>
+--EXPECTF--
+--> Access the real property:
+bool(true)
+string(15) "object property"
+string(23) "object property.changed"
+
+--> Remove the real property and access the array element:
+bool(true)
+string(13) "array element"
+string(21) "array element.changed"
+
+--> Remove the array element and try access again:
+bool(false)
+
+Notice: Undefined index: p in %s on line 10
+NULL
+
+Notice: Undefined index: p in %s on line 12
+string(8) ".changed"
diff --git a/ext/spl/tests/arrayObject_setFlags_basic2.phpt b/ext/spl/tests/arrayObject_setFlags_basic2.phpt
new file mode 100644
index 0000000..806f812
--- /dev/null
+++ b/ext/spl/tests/arrayObject_setFlags_basic2.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: Ensure access to non-visible properties falls back to dimension access with ArrayObject::ARRAY_AS_PROPS.
+--FILE--
+<?php
+class C extends ArrayObject {
+ private $x = 'secret';
+
+ static function go($c) {
+ var_dump($c->x);
+ }
+}
+
+$c = new C(array('x'=>'public'));
+
+$c->setFlags(ArrayObject::ARRAY_AS_PROPS);
+C::go($c);
+var_dump($c->x);
+
+
+$c->setFlags(0);
+C::go($c);
+var_dump($c->x);
+?>
+--EXPECTF--
+string(6) "secret"
+string(6) "public"
+string(6) "secret"
+
+Fatal error: Cannot access private property C::$x in %s on line 19
diff --git a/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt b/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt
new file mode 100644
index 0000000..4715eea
--- /dev/null
+++ b/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt
@@ -0,0 +1,56 @@
+--TEST--
+SPL: ArrayObject with bad iterator class.
+--FILE--
+<?php
+try {
+ $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3));
+ $ao->setIteratorClass("nonExistentClass");
+ foreach($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+try {
+ $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3));
+ $ao->setIteratorClass("stdClass");
+ foreach($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+
+try {
+ $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "nonExistentClass");
+ foreach($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+try {
+ $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "stdClass");
+ foreach($ao as $key=>$value) {
+ echo " $key=>$value\n";
+ }
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+?>
+--EXPECTF--
+Warning: ArrayObject::setIteratorClass() expects parameter 1 to be a class name derived from Iterator, 'nonExistentClass' given in %s on line 4
+ a=>1
+ b=>2
+ c=>3
+
+Warning: ArrayObject::setIteratorClass() expects parameter 1 to be a class name derived from Iterator, 'stdClass' given in %s on line 14
+ a=>1
+ b=>2
+ c=>3
+string(113) "ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'nonExistentClass' given"
+string(105) "ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'stdClass' given"
diff --git a/ext/spl/tests/arrayObject_uasort_basic1.phpt b/ext/spl/tests/arrayObject_uasort_basic1.phpt
new file mode 100644
index 0000000..203edb6
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uasort_basic1.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: Test ArrayObject::uasort() function : basic functionality
+--FILE--
+<?php
+/* Prototype : int ArrayObject::uasort(callback cmp_function)
+ * Description: proto int ArrayIterator::uasort(callback cmp_function)
+ Sort the entries by values user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::uasort() : basic functionality ***\n";
+
+// Reverse sorter
+function cmp($value1, $value2) {
+ if($value1 == $value2) {
+ return 0;
+ }
+ else if($value1 < $value2) {
+ return 1;
+ }
+ else
+ return -1;
+}
+$ao = new ArrayObject(array(2,3,1));
+
+$ao->uasort('cmp');
+var_dump($ao);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::uasort() : basic functionality ***
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [1]=>
+ int(3)
+ [0]=>
+ int(2)
+ [2]=>
+ int(1)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_uasort_error1.phpt b/ext/spl/tests/arrayObject_uasort_error1.phpt
new file mode 100644
index 0000000..d7306c9
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uasort_error1.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Test ArrayObject::uasort() function : wrong arg count
+--FILE--
+<?php
+/* Prototype : int ArrayObject::uasort(callback cmp_function)
+ * Description: proto int ArrayIterator::uasort(callback cmp_function)
+ Sort the entries by values user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+$ao = new ArrayObject();
+
+try {
+ $ao->uasort();
+} catch (BadMethodCallException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $ao->uasort(1,2);
+} catch (BadMethodCallException $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Function expects exactly one argument
+Function expects exactly one argument
+===DONE===
diff --git a/ext/spl/tests/arrayObject_uksort_basic1.phpt b/ext/spl/tests/arrayObject_uksort_basic1.phpt
new file mode 100644
index 0000000..1581589
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uksort_basic1.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Test ArrayObject::uksort() function : basic functionality
+--FILE--
+<?php
+/* Prototype : int ArrayObject::uksort(callback cmp_function)
+ * Description: proto int ArrayIterator::uksort(callback cmp_function)
+ * Sort the entries by key using user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::uksort() : basic functionality ***\n";
+// Reverse sorter
+function cmp($value1, $value2) {
+ if($value1 == $value2) {
+ return 0;
+ }
+ else if($value1 < $value2) {
+ return 1;
+ }
+ else
+ return -1;
+}
+$ao = new ArrayObject(array(3=>0, 2=>1, 5=>2, 6=>3, 1=>4));
+
+$ao->uksort('cmp');
+var_dump($ao);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::uksort() : basic functionality ***
+object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ [6]=>
+ int(3)
+ [5]=>
+ int(2)
+ [3]=>
+ int(0)
+ [2]=>
+ int(1)
+ [1]=>
+ int(4)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_uksort_error1.phpt b/ext/spl/tests/arrayObject_uksort_error1.phpt
new file mode 100644
index 0000000..d019fc4
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uksort_error1.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Test ArrayObject::uksort() function : wrong arg count
+--FILE--
+<?php
+/* Prototype : int ArrayObject::uksort(callback cmp_function)
+ * Description: proto int ArrayIterator::uksort(callback cmp_function)
+ Sort the entries by key using user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+$ao = new ArrayObject();
+
+try {
+ $ao->uksort();
+} catch (BadMethodCallException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $ao->uksort(1,2);
+} catch (BadMethodCallException $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Function expects exactly one argument
+Function expects exactly one argument
+===DONE===
diff --git a/ext/spl/tests/array_001.phpt b/ext/spl/tests/array_001.phpt
new file mode 100644
index 0000000..b55fcba
--- /dev/null
+++ b/ext/spl/tests/array_001.phpt
@@ -0,0 +1,113 @@
+--TEST--
+SPL: ArrayObject
+--FILE--
+<?php
+
+$ar = array(0=>0, 1=>1);
+$ar = new ArrayObject($ar);
+
+var_dump($ar);
+
+$ar[2] = 2;
+var_dump($ar[2]);
+var_dump($ar["3"] = 3);
+
+var_dump(array_merge((array)$ar, array(4=>4, 5=>5)));
+
+var_dump($ar["a"] = "a");
+
+var_dump($ar);
+var_dump($ar[0]);
+var_dump($ar[6]);
+var_dump($ar["b"]);
+
+unset($ar[1]);
+unset($ar["3"]);
+unset($ar["a"]);
+unset($ar[7]);
+unset($ar["c"]);
+var_dump($ar);
+
+$ar[] = '3';
+$ar[] = 4;
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(2) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(1)
+ }
+}
+int(2)
+int(3)
+array(6) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+ [4]=>
+ int(4)
+ [5]=>
+ int(5)
+}
+string(1) "a"
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+ ["a"]=>
+ string(1) "a"
+ }
+}
+int(0)
+
+Notice: Undefined offset: 6 in %sarray_001.php on line %d
+NULL
+
+Notice: Undefined index: b in %sarray_001.php on line %d
+NULL
+
+Notice: Undefined offset: 7 in %sarray_001.php on line %d
+
+Notice: Undefined index: c in %sarray_001.php on line %d
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(2) {
+ [0]=>
+ int(0)
+ [2]=>
+ int(2)
+ }
+}
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(4) {
+ [0]=>
+ int(0)
+ [2]=>
+ int(2)
+ [4]=>
+ string(1) "3"
+ [5]=>
+ int(4)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/array_002.phpt b/ext/spl/tests/array_002.phpt
new file mode 100644
index 0000000..5593588
--- /dev/null
+++ b/ext/spl/tests/array_002.phpt
@@ -0,0 +1,41 @@
+--TEST--
+SPL: ArrayObject copy constructor
+--FILE--
+<?php
+
+$array = array('1' => 'one',
+ '2' => 'two',
+ '3' => 'three');
+
+$object = new ArrayObject($array);
+$object[] = 'four';
+
+$arrayObject = new ArrayObject($object);
+
+$arrayObject[] = 'five';
+
+var_dump($arrayObject);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ object(ArrayObject)#1 (1) {
+ ["storage":"ArrayObject":private]=>
+ array(5) {
+ [1]=>
+ string(3) "one"
+ [2]=>
+ string(3) "two"
+ [3]=>
+ string(5) "three"
+ [4]=>
+ string(4) "four"
+ [5]=>
+ string(4) "five"
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/array_003.phpt b/ext/spl/tests/array_003.phpt
new file mode 100644
index 0000000..de4ce30
--- /dev/null
+++ b/ext/spl/tests/array_003.phpt
@@ -0,0 +1,63 @@
+--TEST--
+SPL: ArrayObject from object
+--FILE--
+<?php
+
+// This test also needs to exclude the protected and private variables
+// since they cannot be accessed from the external object which iterates
+// them.
+
+class test
+{
+ public $pub = "public";
+ protected $pro = "protected";
+ private $pri = "private";
+
+ function __construct()
+ {
+ $this->imp = "implicit";
+ }
+};
+
+$test = new test;
+$test->dyn = "dynamic";
+
+print_r($test);
+
+$object = new ArrayObject($test);
+
+print_r($object);
+
+foreach($test as $key => $val)
+{
+ echo "$key => $val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+test Object
+(
+ [pub] => public
+ [pro:protected] => protected
+ [pri:test:private] => private
+ [imp] => implicit
+ [dyn] => dynamic
+)
+ArrayObject Object
+(
+ [storage:ArrayObject:private] => test Object
+ (
+ [pub] => public
+ [pro:protected] => protected
+ [pri:test:private] => private
+ [imp] => implicit
+ [dyn] => dynamic
+ )
+
+)
+pub => public
+imp => implicit
+dyn => dynamic
+===DONE===
diff --git a/ext/spl/tests/array_004.phpt b/ext/spl/tests/array_004.phpt
new file mode 100644
index 0000000..0b80e5c
--- /dev/null
+++ b/ext/spl/tests/array_004.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: ArrayIterator
+--FILE--
+<?php
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new ArrayObject($arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==0 && $bk==0) {
+ $arr[0] = "modify";
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>0
+1=>1 - 1=>1
+1=>1 - 2=>2
+2=>2 - 0=>0
+2=>2 - 1=>1
+2=>2 - 2=>2
+Done
diff --git a/ext/spl/tests/array_005.phpt b/ext/spl/tests/array_005.phpt
new file mode 100644
index 0000000..d7ef15d
--- /dev/null
+++ b/ext/spl/tests/array_005.phpt
@@ -0,0 +1,91 @@
+--TEST--
+SPL: ArrayObject/Iterator interaction
+--FILE--
+<?php
+
+class Student
+{
+ private $id;
+ private $name;
+
+ public function __construct($id, $name)
+ {
+ $this->id = $id;
+ $this->name = $name;
+ }
+
+ public function __toString()
+ {
+ return $this->id . ', ' . $this->name;
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+}
+
+class StudentIdFilter extends FilterIterator
+{
+ private $id;
+
+ public function __construct(ArrayObject $students, Student $other)
+ {
+ FilterIterator::__construct($students->getIterator());
+ $this->id = $other->getId();
+ }
+
+ public function accept()
+ {
+ echo "ACCEPT ".$this->current()->getId()." == ".$this->id."\n";
+ return $this->current()->getId() == $this->id;
+ }
+}
+
+class StudentList implements IteratorAggregate
+{
+ private $students;
+
+ public function __construct()
+ {
+ $this->students = new ArrayObject(array());
+ }
+
+ public function add(Student $student)
+ {
+ if (!$this->contains($student)) {
+ $this->students[] = $student;
+ }
+ }
+
+ public function contains(Student $student)
+ {
+ foreach ($this->students as $s)
+ {
+ if ($s->getId() == $student->getId()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function getIterator() {
+ return $this->students->getIterator();
+ }
+}
+
+$students = new StudentList();
+$students->add(new Student('01234123', 'Joe'));
+$students->add(new Student('00000014', 'Bob'));
+$students->add(new Student('00000014', 'Foo'));
+
+foreach ($students as $student) {
+ echo $student, "\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+01234123, Joe
+00000014, Bob
+===DONE===
diff --git a/ext/spl/tests/array_006.phpt b/ext/spl/tests/array_006.phpt
new file mode 100644
index 0000000..49f2838
--- /dev/null
+++ b/ext/spl/tests/array_006.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: ArrayIterator without ArrayObject
+--INI--
+error_reporting=2047
+--FILE--
+<?php
+
+echo "==Normal==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new ArrayIterator($arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==0 && $bk==0) {
+ $arr[0] = "modify";
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+==Normal==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+===DONE===
diff --git a/ext/spl/tests/array_007.phpt b/ext/spl/tests/array_007.phpt
new file mode 100644
index 0000000..7d9bf6a
--- /dev/null
+++ b/ext/spl/tests/array_007.phpt
@@ -0,0 +1,71 @@
+--TEST--
+SPL: ArrayObject/Iterator from IteratorAggregate
+--FILE--
+<?php
+
+// This test also needs to exclude the protected and private variables
+// since they cannot be accessed from the external object which iterates
+// them.
+
+class test implements IteratorAggregate
+{
+ public $pub = "public";
+ protected $pro = "protected";
+ private $pri = "private";
+
+ function __construct()
+ {
+ $this->imp = "implicit";
+ }
+
+ function getIterator()
+ {
+ $it = new ArrayObject($this);
+ return $it->getIterator();
+ }
+};
+
+$test = new test;
+$test->dyn = "dynamic";
+
+print_r($test);
+
+print_r($test->getIterator());
+
+foreach($test as $key => $val)
+{
+ echo "$key => $val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+test Object
+(
+ [pub] => public
+ [pro:protected] => protected
+ [pri:test:private] => private
+ [imp] => implicit
+ [dyn] => dynamic
+)
+ArrayIterator Object
+(
+ [storage:ArrayIterator:private] => ArrayObject Object
+ (
+ [storage:ArrayObject:private] => test Object
+ (
+ [pub] => public
+ [pro:protected] => protected
+ [pri:test:private] => private
+ [imp] => implicit
+ [dyn] => dynamic
+ )
+
+ )
+
+)
+pub => public
+imp => implicit
+dyn => dynamic
+===DONE===
diff --git a/ext/spl/tests/array_008.phpt b/ext/spl/tests/array_008.phpt
new file mode 100644
index 0000000..e7a618d
--- /dev/null
+++ b/ext/spl/tests/array_008.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: ArrayIterator and foreach reference
+--FILE--
+<?php
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new ArrayObject($arr);
+
+foreach($obj as $ak=>&$av) {
+ foreach($obj as $bk=>&$bv) {
+ if ($ak==0 && $bk==0) {
+ $bv = "modify";
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+0=>modify - 0=>modify
+0=>modify - 1=>1
+0=>modify - 2=>2
+1=>1 - 0=>modify
+1=>1 - 1=>1
+1=>1 - 2=>2
+2=>2 - 0=>modify
+2=>2 - 1=>1
+2=>2 - 2=>2
+===DONE===
diff --git a/ext/spl/tests/array_009.phpt b/ext/spl/tests/array_009.phpt
new file mode 100644
index 0000000..fc0d60b
--- /dev/null
+++ b/ext/spl/tests/array_009.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: ArrayIterator implementing RecursiveIterator
+--FILE--
+<?php
+
+$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3);
+
+$dir = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY);
+
+foreach ($dir as $file) {
+ print "$file\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1
+21
+221
+222
+231
+3
+===DONE===
diff --git a/ext/spl/tests/array_009a.phpt b/ext/spl/tests/array_009a.phpt
new file mode 100644
index 0000000..396aa9b
--- /dev/null
+++ b/ext/spl/tests/array_009a.phpt
@@ -0,0 +1,37 @@
+--TEST--
+SPL: ArrayIterator implementing RecursiveIterator
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
+{
+ function hasChildren()
+ {
+ return is_array($this->current());
+ }
+
+ function getChildren()
+ {
+ return new MyRecursiveArrayIterator($this->current());
+ }
+}
+
+$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3);
+
+$dir = new RecursiveIteratorIterator(new MyRecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY);
+
+foreach ($dir as $file) {
+ print "$file\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1
+21
+221
+222
+231
+3
+===DONE===
diff --git a/ext/spl/tests/array_010.phpt b/ext/spl/tests/array_010.phpt
new file mode 100644
index 0000000..d2f3de7
--- /dev/null
+++ b/ext/spl/tests/array_010.phpt
@@ -0,0 +1,144 @@
+--TEST--
+SPL: ArrayIterator implements ArrayAccess
+--FILE--
+<?php
+
+$obj = new ArrayObject(array('1st', 1, 2=>'3rd', '4th'=>4));
+
+var_dump($obj->getArrayCopy());
+
+echo "===EMPTY===\n";
+var_dump(empty($obj[0]));
+var_dump(empty($obj[1]));
+var_dump(empty($obj[2]));
+var_dump(empty($obj['4th']));
+var_dump(empty($obj['5th']));
+var_dump(empty($obj[6]));
+
+echo "===isset===\n";
+var_dump(isset($obj[0]));
+var_dump(isset($obj[1]));
+var_dump(isset($obj[2]));
+var_dump(isset($obj['4th']));
+var_dump(isset($obj['5th']));
+var_dump(isset($obj[6]));
+
+echo "===offsetGet===\n";
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "===offsetSet===\n";
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+echo "===unset===\n";
+var_dump($obj->getArrayCopy());
+unset($obj[2]);
+unset($obj['4th']);
+unset($obj[7]);
+unset($obj['8th']);
+var_dump($obj->getArrayCopy());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+===EMPTY===
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+===isset===
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+===offsetGet===
+string(3) "1st"
+int(1)
+string(3) "3rd"
+int(4)
+
+Notice: Undefined index: 5th in %sarray_010.php on line %d
+NULL
+
+Notice: Undefined offset: 6 in %sarray_010.php on line %d
+NULL
+===offsetSet===
+WRITE 1
+string(9) "Changed 1"
+WRITE 2
+string(11) "Changed 4th"
+WRITE 3
+string(9) "Added 5th"
+WRITE 4
+string(7) "Added 6"
+string(3) "1st"
+string(3) "3rd"
+string(9) "changed 6"
+string(9) "changed 6"
+===unset===
+array(6) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ string(11) "Changed 4th"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+
+Notice: Undefined offset: 7 in %sarray_010.php on line %d
+
+Notice: Undefined index: 8th in %sarray_010.php on line %d
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+===DONE===
diff --git a/ext/spl/tests/array_011.phpt b/ext/spl/tests/array_011.phpt
new file mode 100644
index 0000000..0c5ad55
--- /dev/null
+++ b/ext/spl/tests/array_011.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SPL: ArrayIterator, LimitIterator and string keys
+--FILE--
+<?php
+
+$a = array('zero' => 0, 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5);
+//foreach (new ArrayIterator($a) as $k => $v)
+foreach (new LimitIterator(new ArrayIterator($a), 1, 3) as $k => $v)
+{
+ var_dump(array($k, $v));
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(3) "one"
+ [1]=>
+ int(1)
+}
+array(2) {
+ [0]=>
+ string(3) "two"
+ [1]=>
+ int(2)
+}
+array(2) {
+ [0]=>
+ string(5) "three"
+ [1]=>
+ int(3)
+}
+===DONE===
diff --git a/ext/spl/tests/array_012.phpt b/ext/spl/tests/array_012.phpt
new file mode 100644
index 0000000..2ee9724
--- /dev/null
+++ b/ext/spl/tests/array_012.phpt
@@ -0,0 +1,63 @@
+--TEST--
+SPL: ArrayIterator::count
+--FILE--
+<?php
+
+echo "===Array===\n";
+
+$a = array('zero' => 0, 'one' => 1, 'two' => 2);
+$it = new ArrayIterator($a);
+
+var_dump($it->count());
+foreach($it as $key => $val)
+{
+ echo "$key=>$val\n";
+ var_dump($it->count());
+}
+var_dump($it->count());
+
+echo "===Object===\n";
+
+class test
+{
+ public $zero = 0;
+ protected $pro;
+ public $one = 1;
+ private $pri;
+ public $two = 2;
+}
+
+$o = new test;
+$it = new ArrayIterator($o);
+
+var_dump($it->count());
+foreach($it as $key => $val)
+{
+ echo "$key=>$val\n";
+ var_dump($it->count());
+}
+var_dump($it->count());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===Array===
+int(3)
+zero=>0
+int(3)
+one=>1
+int(3)
+two=>2
+int(3)
+int(3)
+===Object===
+int(3)
+zero=>0
+int(3)
+one=>1
+int(3)
+two=>2
+int(3)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/array_013.phpt b/ext/spl/tests/array_013.phpt
new file mode 100644
index 0000000..3fda538
--- /dev/null
+++ b/ext/spl/tests/array_013.phpt
@@ -0,0 +1,79 @@
+--TEST--
+SPL: ArrayIterator::append
+--FILE--
+<?php
+
+if (!class_exists('NoRewindIterator', false))
+{
+ require_once(dirname(__FILE__) . '/../examples/norewinditerator.inc');
+}
+
+echo "===Array===\n";
+
+$a = array(0 => 'zero', 1 => 'one', 2 => 'two');
+$it = new ArrayIterator($a);
+
+foreach($it as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append('three');
+$it->append('four');
+
+foreach(new NoRewindIterator($it) as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Object===\n";
+
+class test
+{
+ public $zero = 0;
+ protected $pro;
+ public $one = 1;
+ private $pri;
+ public $two = 2;
+}
+
+$o = new test;
+$it = new ArrayIterator($o);
+
+foreach($it as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append('three');
+$it->append('four');
+
+foreach(new NoRewindIterator($it) as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+var_dump($o->{0}); /* doesn't wotk anyway */
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===Array===
+0=>zero
+1=>one
+2=>two
+===Append===
+3=>three
+4=>four
+===Object===
+zero=>0
+one=>1
+two=>2
+===Append===
+
+Catchable fatal error: ArrayIterator::append(): Cannot append properties to objects, use ArrayIterator::offsetSet() instead in %sarray_013.php on line %d
diff --git a/ext/spl/tests/array_014.phpt b/ext/spl/tests/array_014.phpt
new file mode 100644
index 0000000..1ac9d4f
--- /dev/null
+++ b/ext/spl/tests/array_014.phpt
@@ -0,0 +1,59 @@
+--TEST--
+SPL: ArrayIterator::seek()
+--FILE--
+<?php
+
+$it = new ArrayIterator(range(0,10));
+var_dump($it->count());
+$it->seek(5);
+var_dump($it->current());
+$it->seek(4);
+var_dump($it->current());
+try
+{
+ $it->seek(-1);
+ var_dump($it->current());
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+try
+{
+ $it->seek(12);
+ var_dump($it->current());
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+$pos = 0;
+foreach($it as $v)
+{
+ $it->seek($pos++);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(11)
+int(5)
+int(4)
+Seek position -1 is out of range
+Seek position 12 is out of range
+int(0)
+int(1)
+int(2)
+int(3)
+int(4)
+int(5)
+int(6)
+int(7)
+int(8)
+int(9)
+int(10)
+===DONE===
diff --git a/ext/spl/tests/array_015.phpt b/ext/spl/tests/array_015.phpt
new file mode 100644
index 0000000..f0bf9f4
--- /dev/null
+++ b/ext/spl/tests/array_015.phpt
@@ -0,0 +1,97 @@
+--TEST--
+SPL: ArrayIterator::next() with internal arrays
+--FILE--
+<?php
+
+$ar = new ArrayObject();
+
+$ar[0] = 1;
+$ar[1] = 2;
+$ar[2] = 3;
+$ar[3] = 4;
+$ar[4] = 5;
+
+var_dump($ar);
+
+$it = $ar->getIterator();
+
+$ar->offsetUnset($it->key());
+$it->next();
+
+var_dump($it->current());
+var_dump($ar);
+
+foreach($it as $k => $v)
+{
+ $ar->offsetUnset($k+1);
+ echo "$k=>$v\n";
+}
+
+var_dump($ar);
+
+foreach($it as $k => $v)
+{
+ $ar->offsetUnset($k);
+ echo "$k=>$v\n";
+}
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(ArrayObject)#%d (1) {
+ %s"storage"%s"ArrayObject":private]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ }
+}
+
+Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d
+int(2)
+object(ArrayObject)#%d (1) {
+ %s"storage"%s"ArrayObject":private]=>
+ array(4) {
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ }
+}
+1=>2
+3=>4
+object(ArrayObject)#%d (1) {
+ %s"storage"%s"ArrayObject":private]=>
+ array(2) {
+ [1]=>
+ int(2)
+ [3]=>
+ int(4)
+ }
+}
+1=>2
+
+Notice: main(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d
+3=>4
+
+Notice: main(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d
+object(ArrayObject)#%d (1) {
+ %s"storage"%s"ArrayObject":private]=>
+ array(0) {
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/array_016.phpt b/ext/spl/tests/array_016.phpt
new file mode 100644
index 0000000..8637c5c
--- /dev/null
+++ b/ext/spl/tests/array_016.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: ArrayIterator/Object and IteratorIterator
+--FILE--
+<?php
+
+$it = new ArrayIterator(range(0,3));
+
+foreach(new IteratorIterator($it) as $v)
+{
+ var_dump($v);
+}
+
+$it = new ArrayObject(range(0,3));
+
+foreach(new IteratorIterator($it) as $v)
+{
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(0)
+int(1)
+int(2)
+int(3)
+int(0)
+int(1)
+int(2)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/array_017.phpt b/ext/spl/tests/array_017.phpt
new file mode 100644
index 0000000..8f3d345
--- /dev/null
+++ b/ext/spl/tests/array_017.phpt
@@ -0,0 +1,817 @@
+--TEST--
+SPL: ArrayObject::exchangeArray($this)
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ public $pub2 = 1;
+ protected $pro2 = 2;
+ private $pri2 = 3;
+
+ function __construct($ar, $flags = 0)
+ {
+ echo __METHOD__ . "()\n";
+ parent::__construct($ar, $flags);
+ $this->imp2 = 4;
+ }
+
+ function dump()
+ {
+ echo __METHOD__ . "()\n";
+ var_dump(array('Flags'=>$this->getFlags()
+ ,'OVars'=>get_object_vars($this)
+ ,'$this'=>$this));
+ }
+
+ function setFlags($flags)
+ {
+ echo __METHOD__ . "($flags)\n";
+ ArrayIterator::setFlags($flags);
+ }
+}
+
+class ArrayObjectEx extends ArrayObject
+{
+ public $pub1 = 1;
+ protected $pro1 = 2;
+ private $pri1 = 3;
+
+ function __construct($ar = array(), $flags = 0)
+ {
+ echo __METHOD__ . "()\n";
+ parent::__construct($ar, $flags);
+ $this->imp1 = 4;
+ }
+
+ function exchange()
+ {
+ echo __METHOD__ . "()\n";
+ $this->exchangeArray($this);
+ }
+
+ function dump()
+ {
+ echo __METHOD__ . "()\n";
+ var_dump(array('Flags'=>$this->getFlags()
+ ,'OVars'=>get_object_vars($this)
+ ,'$this'=>$this));
+ }
+
+ function show()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $n => $v)
+ {
+ var_dump(array($n => $v));
+ }
+ }
+
+ function setFlags($flags)
+ {
+ echo __METHOD__ . "($flags)\n";
+ ArrayObject::setFlags($flags);
+ }
+
+ function getIterator()
+ {
+ echo __METHOD__ . "()\n";
+ $it = new ArrayIteratorEx($this, $this->getFlags());
+ $it->dyn2 = 5;
+ $it->dump();
+ return $it;
+ }
+}
+
+function check($obj, $flags)
+{
+ echo "===CHECK===\n";
+
+ $obj->setFlags($flags);
+ $obj->dump();
+ $obj->show();
+
+ echo "===FOREACH===\n";
+
+ $it = $obj->getIterator();
+ foreach($it as $n => $v)
+ {
+ var_dump(array($n => $v));
+ }
+
+ echo "===PROPERTY===\n";
+
+ var_dump($obj->pub1);
+ var_dump(isset($obj->a));
+ $obj->setFlags($flags | 2);
+ var_dump($obj->pub1);
+ var_dump(isset($obj->a));
+
+ var_dump($it->pub2);
+ var_dump(isset($it->pub1));
+ $it->setFlags($flags | 2);
+ var_dump($it->pub2);
+ var_dump(isset($it->pub1));
+}
+
+$obj = new ArrayObjectEx(array(0=>1,'a'=>25, 'pub1'=>42), 0);
+$obj->dyn1 = 5;
+
+check($obj, 0);
+check($obj, 1);
+
+echo "#####EXCHANGE#####\n";
+
+$obj->exchange();
+
+check($obj, 0);
+check($obj, 1);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+ArrayObjectEx::__construct()
+===CHECK===
+ArrayObjectEx::setFlags(0)
+ArrayObjectEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(2) {
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ ["$this"]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(2) {
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+ }
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ ["a"]=>
+ int(25)
+}
+array(1) {
+ ["pub1"]=>
+ int(42)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(2) {
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+ }
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ ["a"]=>
+ int(25)
+}
+array(1) {
+ ["pub1"]=>
+ int(42)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(2)
+int(1)
+bool(true)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(2)
+int(1)
+bool(true)
+===CHECK===
+ArrayObjectEx::setFlags(1)
+ArrayObjectEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1"]=>
+ int(2)
+ ["pri1"]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub2"]=>
+ int(1)
+ ["pro2"]=>
+ int(2)
+ ["pri2"]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+ }
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ ["a"]=>
+ int(25)
+}
+array(1) {
+ ["pub1"]=>
+ int(42)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub2"]=>
+ int(1)
+ ["pro2"]=>
+ int(2)
+ ["pri2"]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (6) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ ["a"]=>
+ int(25)
+ ["pub1"]=>
+ int(42)
+ }
+ }
+ }
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ ["a"]=>
+ int(25)
+}
+array(1) {
+ ["pub1"]=>
+ int(42)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(3)
+int(1)
+bool(true)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(3)
+int(1)
+bool(true)
+#####EXCHANGE#####
+ArrayObjectEx::exchange()
+===CHECK===
+ArrayObjectEx::setFlags(0)
+ArrayObjectEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1"]=>
+ int(2)
+ ["pri1"]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(4) {
+ ["pub1"]=>
+ int(1)
+ ["pro1"]=>
+ int(2)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ }
+}
+array(1) {
+ ["pub1"]=>
+ int(1)
+}
+array(1) {
+ ["imp1"]=>
+ int(4)
+}
+array(1) {
+ ["dyn1"]=>
+ int(5)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(0)
+ ["OVars"]=>
+ array(4) {
+ ["pub1"]=>
+ int(1)
+ ["pro1"]=>
+ int(2)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ }
+}
+array(1) {
+ ["pub1"]=>
+ int(1)
+}
+array(1) {
+ ["imp1"]=>
+ int(4)
+}
+array(1) {
+ ["dyn1"]=>
+ int(5)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(2)
+int(1)
+bool(false)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(2)
+int(1)
+bool(true)
+===CHECK===
+ArrayObjectEx::setFlags(1)
+ArrayObjectEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1"]=>
+ int(2)
+ ["pri1"]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub2"]=>
+ int(1)
+ ["pro2"]=>
+ int(2)
+ ["pri2"]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ }
+}
+array(1) {
+ ["pub1"]=>
+ int(1)
+}
+array(1) {
+ ["imp1"]=>
+ int(4)
+}
+array(1) {
+ ["dyn1"]=>
+ int(5)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+ ["Flags"]=>
+ int(1)
+ ["OVars"]=>
+ array(5) {
+ ["pub2"]=>
+ int(1)
+ ["pro2"]=>
+ int(2)
+ ["pri2"]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ }
+ ["$this"]=>
+ object(ArrayIteratorEx)#%d (6) {
+ ["pub2"]=>
+ int(1)
+ ["pro2":protected]=>
+ int(2)
+ ["pri2":"ArrayIteratorEx":private]=>
+ int(3)
+ ["imp2"]=>
+ int(4)
+ ["dyn2"]=>
+ int(5)
+ ["storage":"ArrayIterator":private]=>
+ object(ArrayObjectEx)#%d (5) {
+ ["pub1"]=>
+ int(1)
+ ["pro1":protected]=>
+ int(2)
+ ["pri1":"ArrayObjectEx":private]=>
+ int(3)
+ ["imp1"]=>
+ int(4)
+ ["dyn1"]=>
+ int(5)
+ }
+ }
+}
+array(1) {
+ ["pub1"]=>
+ int(1)
+}
+array(1) {
+ ["imp1"]=>
+ int(4)
+}
+array(1) {
+ ["dyn1"]=>
+ int(5)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(3)
+int(1)
+bool(false)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(3)
+int(1)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/array_018.phpt b/ext/spl/tests/array_018.phpt
new file mode 100644
index 0000000..7c68a62
--- /dev/null
+++ b/ext/spl/tests/array_018.phpt
Binary files differ
diff --git a/ext/spl/tests/array_019.phpt b/ext/spl/tests/array_019.phpt
new file mode 100644
index 0000000..d128f4d
--- /dev/null
+++ b/ext/spl/tests/array_019.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: ArrayIterator and foreach by reference
+--FILE--
+<?php
+
+$ar = new ArrayObject(array(1)); foreach($ar as &$v) var_dump($v);
+$ar = new ArrayIterator(array(2)); foreach($ar as &$v) var_dump($v);
+$ar = new RecursiveArrayIterator(array(3)); foreach($ar as &$v) var_dump($v);
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ function current()
+ {
+ return ArrayIterator::current();
+ }
+}
+
+$ar = new ArrayIteratorEx(array(4)); foreach($ar as $v) var_dump($v);
+$ar = new ArrayIteratorEx(array(5)); foreach($ar as &$v) var_dump($v);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+int(2)
+int(3)
+int(4)
+
+Fatal error: An iterator cannot be used with foreach by reference in %sarray_019.php on line %d
diff --git a/ext/spl/tests/array_020.phpt b/ext/spl/tests/array_020.phpt
new file mode 100644
index 0000000..4c6fe0d
--- /dev/null
+++ b/ext/spl/tests/array_020.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: ArrayIterator overloading
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ ArrayIterator::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return ArrayIterator::valid();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return ArrayIterator::key();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return ArrayIterator::current();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ return ArrayIterator::next();
+ }
+}
+
+$ar = new ArrayIteratorEx(array(1,2));
+foreach($ar as $k => $v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+ArrayIteratorEx::rewind
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(0)
+int(1)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(1)
+int(2)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+===DONE===
diff --git a/ext/spl/tests/array_021.phpt b/ext/spl/tests/array_021.phpt
new file mode 100644
index 0000000..f2ae0c8
--- /dev/null
+++ b/ext/spl/tests/array_021.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: ArrayObject::seek() and exceptions
+--FILE--
+<?php
+
+class foo extends ArrayObject
+{
+ public function seek($key)
+ {
+ echo __METHOD__ . "($key)\n";
+ throw new Exception("hi");
+ }
+}
+
+$test = new foo(array(1,2,3));
+
+try
+{
+ $test->seek('bar');
+}
+catch (Exception $e)
+{
+ echo "got exception\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+foo::seek(bar)
+got exception
+===DONE===
diff --git a/ext/spl/tests/array_022.phpt b/ext/spl/tests/array_022.phpt
new file mode 100644
index 0000000..82da3bb
--- /dev/null
+++ b/ext/spl/tests/array_022.phpt
@@ -0,0 +1,80 @@
+--TEST--
+SPL: ArrayObject/Iterator and reference to self
+--FILE--
+==ArrayObject===
+<?php
+
+class MyArrayObject extends ArrayObject
+{
+ public function __construct()
+ {
+ parent::__construct($this);
+ $this['bar'] = 'baz';
+ }
+}
+
+$a = new MyArrayObject;
+
+$b = clone $a;
+$b['baz'] = 'Foo';
+
+var_dump($a);
+var_dump($b);
+
+?>
+==ArrayIterator===
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ public function __construct()
+ {
+ parent::__construct($this);
+ $this['bar'] = 'baz';
+ }
+}
+
+$a = new MyArrayIterator;
+
+$b = clone $a;
+$b['baz'] = 'Foo';
+
+var_dump($a);
+var_dump($b);
+
+?>
+===DONE===
+--EXPECTF--
+==ArrayObject===
+object(MyArrayObject)#%d (1) {
+ ["bar"]=>
+ string(3) "baz"
+}
+object(MyArrayObject)#%d (3) {
+ ["bar"]=>
+ string(3) "baz"
+ ["baz"]=>
+ string(3) "Foo"
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["bar"]=>
+ string(3) "baz"
+ }
+}
+==ArrayIterator===
+object(MyArrayIterator)#%d (1) {
+ ["bar"]=>
+ string(3) "baz"
+}
+object(MyArrayIterator)#%d (3) {
+ ["bar"]=>
+ string(3) "baz"
+ ["baz"]=>
+ string(3) "Foo"
+ ["storage":"ArrayIterator":private]=>
+ object(MyArrayIterator)#%d (1) {
+ ["bar"]=>
+ string(3) "baz"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/array_023.phpt b/ext/spl/tests/array_023.phpt
new file mode 100644
index 0000000..a444604
--- /dev/null
+++ b/ext/spl/tests/array_023.phpt
@@ -0,0 +1,87 @@
+--TEST--
+Testing class extending to ArrayObject and serialize
+--FILE--
+<?php
+
+class Name extends ArrayObject
+{
+ public $var = 'a';
+ protected $bar = 'b';
+ private $foo = 'c';
+}
+
+$a = new Name();
+var_dump($a);
+var_dump($a->var);
+
+$a = unserialize(serialize($a));
+
+var_dump($a);
+var_dump($a->var);
+
+class Bla extends ArrayObject
+{
+ public $var = 'aaa';
+ protected $bar = 'bbb';
+ private $foo = 'ccc';
+}
+
+$a = new Bla();
+var_dump($a);
+var_dump($a->var);
+
+$a = unserialize(serialize($a));
+
+var_dump($a);
+var_dump($a->var);
+
+?>
+--EXPECT--
+object(Name)#1 (4) {
+ ["var"]=>
+ string(1) "a"
+ ["bar":protected]=>
+ string(1) "b"
+ ["foo":"Name":private]=>
+ string(1) "c"
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+string(1) "a"
+object(Name)#2 (4) {
+ ["var"]=>
+ string(1) "a"
+ ["bar":protected]=>
+ string(1) "b"
+ ["foo":"Name":private]=>
+ string(1) "c"
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+string(1) "a"
+object(Bla)#1 (4) {
+ ["var"]=>
+ string(3) "aaa"
+ ["bar":protected]=>
+ string(3) "bbb"
+ ["foo":"Bla":private]=>
+ string(3) "ccc"
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+string(3) "aaa"
+object(Bla)#2 (4) {
+ ["var"]=>
+ string(3) "aaa"
+ ["bar":protected]=>
+ string(3) "bbb"
+ ["foo":"Bla":private]=>
+ string(3) "ccc"
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+string(3) "aaa"
diff --git a/ext/spl/tests/array_024.phpt b/ext/spl/tests/array_024.phpt
new file mode 100644
index 0000000..0c073bf
--- /dev/null
+++ b/ext/spl/tests/array_024.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: ArrayObject with overriden count()
+--FILE--
+<?php
+$obj = new ArrayObject(array(1,2));
+var_dump(count($obj));
+class ArrayObject2 extends ArrayObject {
+ public function count() {
+ return -parent::count();
+ }
+}
+$obj = new ArrayObject2(array(1,2));
+var_dump(count($obj));
+?>
+--EXPECT--
+int(2)
+int(-2)
diff --git a/ext/spl/tests/array_025.phpt b/ext/spl/tests/array_025.phpt
new file mode 100644
index 0000000..35893ea
--- /dev/null
+++ b/ext/spl/tests/array_025.phpt
@@ -0,0 +1,40 @@
+--TEST--
+SPL: ArrayObject serialize with an object as storage
+--FILE--
+<?php
+$obj1 = new ArrayObject(new ArrayObject(array(1,2)));
+$s = serialize($obj1);
+$obj2 = unserialize($s);
+
+print_r($obj1);
+echo "$s\n";
+print_r($obj2);
+?>
+--EXPECT--
+ArrayObject Object
+(
+ [storage:ArrayObject:private] => ArrayObject Object
+ (
+ [storage:ArrayObject:private] => Array
+ (
+ [0] => 1
+ [1] => 2
+ )
+
+ )
+
+)
+C:11:"ArrayObject":76:{x:i:0;C:11:"ArrayObject":37:{x:i:0;a:2:{i:0;i:1;i:1;i:2;};m:a:0:{}};m:a:0:{}}
+ArrayObject Object
+(
+ [storage:ArrayObject:private] => ArrayObject Object
+ (
+ [storage:ArrayObject:private] => Array
+ (
+ [0] => 1
+ [1] => 2
+ )
+
+ )
+
+)
diff --git a/ext/spl/tests/array_026.phpt b/ext/spl/tests/array_026.phpt
new file mode 100644
index 0000000..9c79c57
--- /dev/null
+++ b/ext/spl/tests/array_026.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: ArrayObject indirect offsetGet overwriting EG(uninitialized_zvar_ptr)
+--FILE--
+<?php
+$test = new ArrayObject();
+$test['d1']['d2'] = 'hello';
+$test['d1']['d3'] = 'world';
+var_dump($test, $test3['mmmmm']);
+?>
+--EXPECTF--
+Notice: Undefined variable: test3 in %s%earray_026.php on line %d
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["d1"]=>
+ array(2) {
+ ["d2"]=>
+ string(5) "hello"
+ ["d3"]=>
+ string(5) "world"
+ }
+ }
+}
+NULL
diff --git a/ext/spl/tests/array_027.phpt b/ext/spl/tests/array_027.phpt
new file mode 100644
index 0000000..509b8f9
--- /dev/null
+++ b/ext/spl/tests/array_027.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: ArrayObject revursive var_dump
+--FILE--
+<?php
+class AO extends ArrayObject {
+}
+$o = new AO();
+$o['plop'] = $o;
+
+var_dump($o);
+--EXPECTF--
+object(AO)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(1) {
+ ["plop"]=>
+ *RECURSION*
+ }
+}
diff --git a/ext/spl/tests/bug28822.phpt b/ext/spl/tests/bug28822.phpt
new file mode 100644
index 0000000..7114eda
--- /dev/null
+++ b/ext/spl/tests/bug28822.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #28822 (ArrayObject::offsetExists() works inverted)
+--FILE--
+<?php
+
+$array = new ArrayObject();
+$array->offsetSet('key', 'value');
+var_dump($array->offsetExists('key'));
+var_dump($array->offsetExists('nokey'));
+
+?>
+===DONE===
+--EXPECT--
+bool(true)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/bug31185.phpt b/ext/spl/tests/bug31185.phpt
new file mode 100644
index 0000000..aa410eb
--- /dev/null
+++ b/ext/spl/tests/bug31185.phpt
@@ -0,0 +1,61 @@
+--TEST--
+Bug #31185 (Crash when exceptions thrown from ArrayAccess::offsetUnset())
+--FILE--
+<?php
+
+class FooBar implements ArrayAccess {
+ private $array = array();
+
+ public function offsetExists($index) {
+ return isset($this->array[$index]);
+ }
+
+ public function offsetGet($index) {
+ return $this->array[$index];
+ }
+
+ public function offsetSet($index, $value) {
+ echo __METHOD__ . "($index, $value)\n";
+ $this->array[$index] = $value;
+ }
+
+ public function offsetUnset($index) {
+ throw new Exception('FAIL');
+ unset($this->array[$index]);
+ }
+
+}
+
+$i = 0; $j = 0;
+$foo = new FooBar();
+$foo[$j++] = $i++;
+$foo[$j++] = $i++;
+$foo[$j++] = $i++;
+try
+{
+ unset($foo[1]);
+}
+catch (Exception $e)
+{
+ echo "CAUGHT: " . $e->getMessage() . "\n";
+}
+
+print_R($foo);
+?>
+===DONE===
+--EXPECT--
+FooBar::offsetSet(0, 0)
+FooBar::offsetSet(1, 1)
+FooBar::offsetSet(2, 2)
+CAUGHT: FAIL
+FooBar Object
+(
+ [array:FooBar:private] => Array
+ (
+ [0] => 0
+ [1] => 1
+ [2] => 2
+ )
+
+)
+===DONE===
diff --git a/ext/spl/tests/bug31346.phpt b/ext/spl/tests/bug31346.phpt
new file mode 100644
index 0000000..9b5618e
--- /dev/null
+++ b/ext/spl/tests/bug31346.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #31486 (ArrayIterator::next segfaults)
+--FILE--
+<?php
+$obj = new stdClass;
+$obj->var1=1;
+
+$ao = new ArrayObject($obj);
+
+$i = $ao->getIterator();
+
+$ao->offsetUnset($i->key());
+$i->next();
+
+?>
+===DONE===
+--EXPECTF--
+Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sbug31346.php on line %d
+===DONE===
diff --git a/ext/spl/tests/bug31348.phpt b/ext/spl/tests/bug31348.phpt
new file mode 100644
index 0000000..047e4b2
--- /dev/null
+++ b/ext/spl/tests/bug31348.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #31348 (CachingIterator::rewind() leaks)
+--FILE--
+<?php
+$a = Array("some","blah");
+$i = new ArrayIterator($a);
+
+$ci = new CachingIterator($i);
+
+$ci->rewind();
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/ext/spl/tests/bug31926.phpt b/ext/spl/tests/bug31926.phpt
new file mode 100644
index 0000000..2d72df4
--- /dev/null
+++ b/ext/spl/tests/bug31926.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #31926 (php in free() error with RecursiveArrayIterator)
+--FILE--
+<?php
+
+$array = array(0 => array('world'));
+
+$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
+foreach($it as $key => $val) {
+ var_dump($key, $val);
+}
+
+?>
+--EXPECT--
+int(0)
+string(5) "world"
diff --git a/ext/spl/tests/bug32134.phpt b/ext/spl/tests/bug32134.phpt
new file mode 100644
index 0000000..5a880b3
--- /dev/null
+++ b/ext/spl/tests/bug32134.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Bug #32134 (Overloading offsetGet/offsetSet)
+--FILE--
+<?php
+
+class myArray extends ArrayIterator
+{
+
+ public function __construct($array = array())
+ {
+ parent::__construct($array);
+ }
+
+ public function offsetGet($index)
+ {
+ static $i = 0;
+ echo __METHOD__ . "($index)\n";
+ if (++$i > 3) exit(1);
+ return parent::offsetGet($index);
+ }
+
+ public function offsetSet($index, $newval)
+ {
+ echo __METHOD__ . "($index,$newval)\n";
+ return parent::offsetSet($index, $newval);
+ }
+
+}
+
+$myArray = new myArray();
+
+$myArray->offsetSet('one', 'one');
+var_dump($myArray->offsetGet('one'));
+
+$myArray['two'] = 'two';
+var_dump($myArray['two']);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+myArray::offsetSet(one,one)
+myArray::offsetGet(one)
+string(3) "one"
+myArray::offsetSet(two,two)
+myArray::offsetGet(two)
+string(3) "two"
+===DONE===
diff --git a/ext/spl/tests/bug32394.phpt b/ext/spl/tests/bug32394.phpt
new file mode 100644
index 0000000..8189b23
--- /dev/null
+++ b/ext/spl/tests/bug32394.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #32394 (offsetUnset() segfaults in a foreach)
+--FILE--
+<?php
+
+$object = new ArrayIterator;
+$object->append(1);
+
+foreach($object as $key => $value)
+{
+ $object->offsetUnset($key);
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/ext/spl/tests/bug33136.phpt b/ext/spl/tests/bug33136.phpt
new file mode 100644
index 0000000..121ff58
--- /dev/null
+++ b/ext/spl/tests/bug33136.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Bug #33136 (method offsetSet in class extended from ArrayObject crash PHP)
+--FILE--
+<?php
+
+class Collection extends ArrayObject
+{
+ private $data;
+
+ function __construct()
+ {
+ $this->data = array();
+ parent::__construct($this->data);
+ }
+
+ function offsetGet($index)
+ {
+ echo __METHOD__ . "($index)\n";
+ return parent::offsetGet($index);
+ }
+
+ function offsetSet($index, $value)
+ {
+ echo __METHOD__ . "(" . (is_null($index) ? "NULL" : $index) . ",$value)\n";
+ parent::offsetSet($index, $value);
+ }
+}
+
+echo "\n\nInitiate Obj\n";
+$arrayObj = new Collection();
+
+echo "Assign values\n";
+
+$arrayObj[] = "foo";
+var_dump($arrayObj[0]);
+
+$arrayObj[] = "bar";
+var_dump($arrayObj[0]);
+var_dump($arrayObj[1]);
+
+$arrayObj["foo"] = "baz";
+var_dump($arrayObj["foo"]);
+
+print_r($arrayObj);
+
+var_dump(count($arrayObj));
+
+?>
+===DONE===
+<?php //exit(0); ?>
+--EXPECT--
+Initiate Obj
+Assign values
+Collection::offsetSet(NULL,foo)
+Collection::offsetGet(0)
+string(3) "foo"
+Collection::offsetSet(NULL,bar)
+Collection::offsetGet(0)
+string(3) "foo"
+Collection::offsetGet(1)
+string(3) "bar"
+Collection::offsetSet(foo,baz)
+Collection::offsetGet(foo)
+string(3) "baz"
+Collection Object
+(
+ [data:Collection:private] => Array
+ (
+ )
+
+ [storage:ArrayObject:private] => Array
+ (
+ [0] => foo
+ [1] => bar
+ [foo] => baz
+ )
+
+)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/bug34548.phpt b/ext/spl/tests/bug34548.phpt
new file mode 100644
index 0000000..27c3094
--- /dev/null
+++ b/ext/spl/tests/bug34548.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Bug #34548 (Method append() in class extended from ArrayObject crashes PHP)
+--FILE--
+<?php
+
+class Collection extends ArrayObject
+{
+ public function add($dataArray)
+ {
+ foreach($dataArray as $value) $this->append($value);
+ }
+
+ public function offsetSet($index, $value)
+ {
+ parent::offsetSet($index, $value);
+ }
+}
+
+$data1=array('one', 'two', 'three');
+$data2=array('four', 'five');
+
+$foo=new Collection($data1);
+$foo->add($data2);
+
+print_r($foo->getArrayCopy());
+
+echo "Done\n";
+?>
+--EXPECT--
+Array
+(
+ [0] => one
+ [1] => two
+ [2] => three
+ [3] => four
+ [4] => five
+)
+Done
diff --git a/ext/spl/tests/bug36258.phpt b/ext/spl/tests/bug36258.phpt
new file mode 100644
index 0000000..60817d0
--- /dev/null
+++ b/ext/spl/tests/bug36258.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #36258 (SplFileObject::getPath() may lead to segfault)
+--FILE--
+<?php
+
+$diriter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('.') );
+
+foreach ($diriter as $key => $file) {
+ var_dump($file->getFilename());
+ var_dump($file->getPath());
+ break;
+}
+
+?>
+===DONE===
+--EXPECTF--
+string(%d) "%s"
+string(%d) "%s"
+===DONE===
diff --git a/ext/spl/tests/bug36287.phpt b/ext/spl/tests/bug36287.phpt
new file mode 100644
index 0000000..0c3f287
--- /dev/null
+++ b/ext/spl/tests/bug36287.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #36287 (Segfault with SplFileInfo conversion)
+--FILE--
+<?php
+
+$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."), true);
+
+$idx = 0;
+foreach($it as $file)
+{
+ echo "First\n";
+ var_Dump($file->getFilename());
+ echo "Second\n";
+ var_dump($file->getFilename());
+ if (++$idx > 1)
+ {
+ break;
+ }
+}
+
+?>
+===DONE===
+--EXPECTF--
+First
+string(%d) "%s"
+Second
+string(%d) "%s"
+First
+string(%d) "%s"
+Second
+string(%d) "%s"
+===DONE===
diff --git a/ext/spl/tests/bug36825.phpt b/ext/spl/tests/bug36825.phpt
new file mode 100644
index 0000000..35de013
--- /dev/null
+++ b/ext/spl/tests/bug36825.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Bug #36825 (Exceptions thrown in ArrayObject::offsetGet cause segfault)
+--FILE--
+<?php
+
+class foo extends ArrayObject
+{
+ public function offsetGet($key)
+ {
+ echo __METHOD__ . "($key)\n";
+ throw new Exception("hi");
+ }
+}
+
+$test = new foo();
+
+try
+{
+ var_dump($test['bar']);
+}
+catch (Exception $e)
+{
+ echo "got exception\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+foo::offsetGet(bar)
+got exception
+===DONE===
diff --git a/ext/spl/tests/bug36941.phpt b/ext/spl/tests/bug36941.phpt
new file mode 100644
index 0000000..528ba4a
--- /dev/null
+++ b/ext/spl/tests/bug36941.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Bug #36941 (ArrayIterator does not clone itself)
+--FILE--
+===ArrayObject===
+<?php
+$a = new ArrayObject();
+$a[] = 1;
+
+$b = clone $a;
+
+var_dump($a[0], $b[0]);
+$b[0] = $b[0] + 1;
+var_dump($a[0], $b[0]);
+$b[0] = 3;
+var_dump($a[0], $b[0]);
+?>
+===ArrayIterator===
+<?php
+$a = new ArrayIterator();
+$a[] = 1;
+
+$b = clone $a;
+
+var_dump($a[0], $b[0]);
+$b[0] = $b[0] + 1;
+var_dump($a[0], $b[0]);
+$b[0] = 3;
+var_dump($a[0], $b[0]);
+?>
+===DONE===
+--EXPECT--
+===ArrayObject===
+int(1)
+int(1)
+int(1)
+int(2)
+int(1)
+int(3)
+===ArrayIterator===
+int(1)
+int(1)
+int(2)
+int(2)
+int(3)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/bug37457.phpt b/ext/spl/tests/bug37457.phpt
new file mode 100644
index 0000000..e66fa4d
--- /dev/null
+++ b/ext/spl/tests/bug37457.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Bug #37457 (Crash when an exception is thrown in accept() method of FilterIterator)
+--FILE--
+<?php
+
+class Collection implements Iterator
+{
+ protected $array, $valid = false;
+
+ public function __construct(array $a)
+ {
+ echo __METHOD__ . "\n";
+ $this->array = $a;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return current($this->array);
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return key($this->array);
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->valid = (false !== next($this->array));
+ }
+
+ public function valid()
+ {
+ echo __METHOD__ . "\n";
+ return $this->valid;
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->valid = (false !== reset($this->array));
+ }
+}
+
+class TestFilter extends FilterIterator
+{
+ public function accept()
+ {
+ echo __METHOD__ . "\n";
+ throw new Exception("Failure in Accept");
+ }
+}
+
+$test = new TestFilter(new Collection(array(0)));
+
+try
+{
+ foreach ($test as $item)
+ {
+ echo $item;
+ }
+}
+catch (Exception $e)
+{
+ var_dump($e->getMessage());
+}
+
+?>
+===DONE===
+--EXPECTF--
+Collection::__construct
+Collection::rewind
+Collection::valid
+Collection::current
+Collection::key
+TestFilter::accept
+string(17) "Failure in Accept"
+===DONE===
diff --git a/ext/spl/tests/bug38325.phpt b/ext/spl/tests/bug38325.phpt
new file mode 100644
index 0000000..ddb2829
--- /dev/null
+++ b/ext/spl/tests/bug38325.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Bug #38325 (spl_autoload_register() gaves wrong line for "class not found")
+--FILE--
+<?php
+spl_autoload_register();
+new ThisClassDoesNotExistEverFoo();
+?>
+--EXPECTF--
+Fatal error: spl_autoload(): Class ThisClassDoesNotExistEverFoo could not be loaded in %s on line 3
diff --git a/ext/spl/tests/bug38618.phpt b/ext/spl/tests/bug38618.phpt
new file mode 100644
index 0000000..17439b4
--- /dev/null
+++ b/ext/spl/tests/bug38618.phpt
@@ -0,0 +1,105 @@
+--TEST--
+Bug #38618 (RecursiveArrayIterator::hasChildren() follows objects)
+--FILE--
+<?php # vim:ft=php
+
+class FruitPublic
+{
+ public $title;
+
+ public function __construct($title)
+ {
+ $this->title = $title;
+ }
+
+ public function __toString()
+ {
+ return $this->title;
+ }
+}
+
+class FruitProtected
+{
+ protected $title;
+
+ public function __construct($title)
+ {
+ $this->title = $title;
+ }
+
+ public function __toString()
+ {
+ return $this->title;
+ }
+}
+
+function test_array($array, $which, $flags = 0)
+{
+ echo "===$which===\n";
+ $it = new RecursiveArrayIterator($array, $flags);
+ foreach (new RecursiveIteratorIterator($it) as $k => $fruit) {
+ echo $k , ' => ', $fruit, "\n";
+ }
+}
+
+$array = array(
+ 1 => array(
+ 1 => array(
+ 1 => 'apple',
+ ),
+ 2 => array(
+ 1 => 'grape',
+ ),
+ ),
+);
+
+test_array($array, 'Default with array');
+
+$array = array(
+ 1 => array(
+ 1 => array(
+ 1 => new FruitPublic('apple'),
+ ),
+ 2 => array(
+ 1 => new FruitPublic('grape'),
+ ),
+ ),
+);
+
+test_array($array, 'Public Property');
+
+$array = array(
+ 1 => array(
+ 1 => array(
+ 1 => new FruitProtected('apple'),
+ ),
+ 2 => array(
+ 1 => new FruitProtected('grape'),
+ ),
+ ),
+);
+
+test_array($array, 'Protected Property');
+
+test_array($array, 'Public Property New', RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
+test_array($array, 'Protected Property New', RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
+?>
+===DONE===
+<?php exit(0); ?>
+?>
+===DONE===
+--EXPECTF--
+===Default with array===
+1 => apple
+1 => grape
+===Public Property===
+title => apple
+title => grape
+===Protected Property===
+===Public Property New===
+1 => apple
+1 => grape
+===Protected Property New===
+1 => apple
+1 => grape
+===DONE===
diff --git a/ext/spl/tests/bug40036.phpt b/ext/spl/tests/bug40036.phpt
new file mode 100644
index 0000000..8180c03
--- /dev/null
+++ b/ext/spl/tests/bug40036.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #40036 (empty() does not work correctly with ArrayObject when using ARRAY_AS_PROPS)
+--FILE--
+<?php
+class View extends ArrayObject
+{
+ public function __construct(array $array = array())
+ {
+ parent::__construct($array, ArrayObject::ARRAY_AS_PROPS);
+ }
+}
+
+$view = new View();
+$view->foo = false;
+$view->bar = null;
+$view->baz = '';
+if (empty($view['foo']) || empty($view->foo)) {
+ echo "View::foo empty\n";
+}
+if (empty($view['bar']) || empty($view->bar)) {
+ echo "View::bar empty\n";
+}
+if (empty($view['baz']) || empty($view->baz)) {
+ echo "View::baz empty\n";
+}
+?>
+===DONE===
+--EXPECT--
+View::foo empty
+View::bar empty
+View::baz empty
+===DONE===
diff --git a/ext/spl/tests/bug40091.phpt b/ext/spl/tests/bug40091.phpt
new file mode 100644
index 0000000..eb157e7
--- /dev/null
+++ b/ext/spl/tests/bug40091.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Bug #40091 (issue with spl_autoload_register() and 2 instances of the same class)
+--FILE--
+<?php
+class MyAutoloader {
+ function __construct($directory_to_use) {}
+ function autoload($class_name) {
+ // code to autoload based on directory
+ }
+}
+
+$autloader1 = new MyAutoloader('dir1');
+spl_autoload_register(array($autloader1, 'autoload'));
+
+$autloader2 = new MyAutoloader('dir2');
+spl_autoload_register(array($autloader2, 'autoload'));
+
+print_r(spl_autoload_functions());
+?>
+===DONE===
+--EXPECT--
+Array
+(
+ [0] => Array
+ (
+ [0] => MyAutoloader Object
+ (
+ )
+
+ [1] => autoload
+ )
+
+ [1] => Array
+ (
+ [0] => MyAutoloader Object
+ (
+ )
+
+ [1] => autoload
+ )
+
+)
+===DONE===
diff --git a/ext/spl/tests/bug40442.phpt b/ext/spl/tests/bug40442.phpt
new file mode 100644
index 0000000..fbeb22d
--- /dev/null
+++ b/ext/spl/tests/bug40442.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #40442 (ArrayObject::offsetExists broke in 5.2.1, works in 5.2.0)
+--FILE--
+<?php
+$a = new ArrayObject();
+$a->offsetSet('property', 0);
+var_dump($a->offsetExists('property'));
+?>
+===DONE===
+--EXPECT--
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/bug40872.phpt b/ext/spl/tests/bug40872.phpt
new file mode 100644
index 0000000..a48fe74
--- /dev/null
+++ b/ext/spl/tests/bug40872.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #40872 (inconsistency in offsetSet, offsetExists treatment of string enclosed integers)
+--FILE--
+<?php
+ class Project {
+ public $id;
+
+ function __construct($id) {
+ $this->id = $id;
+ }
+ }
+
+ class ProjectsList extends ArrayIterator {
+ public function add(Project $item) {
+ $this->offsetSet($item->id, $item);
+ }
+ }
+
+ $projects = new ProjectsList();
+ $projects->add(new Project('1'));
+ $projects->add(new Project(2));
+
+ var_dump($projects->offsetExists(1));
+ var_dump($projects->offsetExists('2'));
+?>
+===DONE===
+--EXPECT--
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/bug41528.phpt b/ext/spl/tests/bug41528.phpt
new file mode 100644
index 0000000..6be82c1
--- /dev/null
+++ b/ext/spl/tests/bug41528.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug #41528 (Classes extending ArrayObject do not serialize correctly)
+--FILE--
+<?php
+class ClassOne extends ArrayObject
+{
+ public $a = 2;
+}
+
+$classOne = new ClassOne();
+$classOne->a = 1;
+
+var_dump($classOne);
+var_dump($classOne->a);
+
+$classOne = unserialize(serialize($classOne));
+
+var_dump($classOne);
+var_dump($classOne->a);
+?>
+--EXPECT--
+object(ClassOne)#1 (2) {
+ ["a"]=>
+ int(1)
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+int(1)
+object(ClassOne)#2 (2) {
+ ["a"]=>
+ int(1)
+ ["storage":"ArrayObject":private]=>
+ array(0) {
+ }
+}
+int(1)
diff --git a/ext/spl/tests/bug41691.phpt b/ext/spl/tests/bug41691.phpt
new file mode 100644
index 0000000..3cf3d87
--- /dev/null
+++ b/ext/spl/tests/bug41691.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #41691 (ArrayObject::exchangeArray hangs Apache)
+--FILE--
+<?php
+
+class A extends ArrayObject {
+ public function __construct($dummy, $flags) {
+ parent::__construct($this, $flags);
+ }
+ public $a;
+ public $b;
+ public $c;
+}
+
+$a = new A(null, ArrayObject::ARRAY_AS_PROPS );
+var_dump($a->exchangeArray(array('a'=>1,'b'=>1,'c'=>1)));
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(3) {
+ ["a"]=>
+ NULL
+ ["b"]=>
+ NULL
+ ["c"]=>
+ NULL
+}
+Done
diff --git a/ext/spl/tests/bug41692.phpt b/ext/spl/tests/bug41692.phpt
new file mode 100644
index 0000000..c9b7d8d
--- /dev/null
+++ b/ext/spl/tests/bug41692.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Bug #41692 (ArrayObject shows weird behaviour in respect to inheritance)
+--FILE--
+<?php
+
+class Bar extends ArrayObject {
+ private $foo = array( 1, 2, 3 );
+ function __construct()
+ {
+ parent::__construct($this->foo);
+ }
+}
+
+$foo = new Bar();
+var_dump($foo);
+$foo['foo'] = 23;
+
+$bar = new Bar();
+var_dump($bar);
+
+echo "Done\n";
+?>
+--EXPECTF--
+object(Bar)#%d (2) {
+ ["foo":"Bar":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+object(Bar)#%d (2) {
+ ["foo":"Bar":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["storage":"ArrayObject":private]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+}
+Done
diff --git a/ext/spl/tests/bug41828.phpt b/ext/spl/tests/bug41828.phpt
new file mode 100644
index 0000000..6053e0e
--- /dev/null
+++ b/ext/spl/tests/bug41828.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Bug #41828 (Segfault if extended constructor of RecursiveIterator doesn't call its parent)
+--FILE--
+<?php
+class foo extends RecursiveIteratorIterator {
+
+ public function __construct($str) {
+ }
+
+ public function bar() {
+ }
+}
+
+$foo = new foo("This is bar");
+echo $foo->bar();
+
+?>
+==DONE==
+<?php exit(0); ?>
+--EXPECTF--
+Fatal error: main(): The foo instance wasn't initialized properly in %s on line %d
diff --git a/ext/spl/tests/bug42364.phpt b/ext/spl/tests/bug42364.phpt
new file mode 100644
index 0000000..971fcc5
--- /dev/null
+++ b/ext/spl/tests/bug42364.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #42364 (Crash when using getRealPath with DirectoryIterator)
+--FILE--
+<?php
+$it = new DirectoryIterator(dirname(__FILE__));
+
+$count = 0;
+
+foreach ($it as $e) {
+ $count++;
+ $type = gettype($e->getRealPath());
+ if ($type != "string" && $type != "unicode") {
+ echo $e->getFilename(), " is a ", gettype($e->getRealPath()), "\n";
+ }
+}
+
+if ($count > 0) {
+ echo "Found $count entries!\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Found %i entries!
+===DONE===
diff --git a/ext/spl/tests/bug42654.phpt b/ext/spl/tests/bug42654.phpt
new file mode 100644
index 0000000..20aad74
--- /dev/null
+++ b/ext/spl/tests/bug42654.phpt
@@ -0,0 +1,158 @@
+--TEST--
+Bug #42654 (RecursiveIteratorIterator modifies only part of leaves)
+--FILE--
+<?php
+$data = array(1 => 'val1',
+ array(2 => 'val2',
+ array(3 => 'val3'),
+ ),
+ 4 => 'val4'
+ );
+
+$iterator = new RecursiveIteratorIterator(new
+RecursiveArrayIterator($data));
+foreach($iterator as $foo) {
+ $key = $iterator->key();
+ echo "update $key\n";
+ var_dump($iterator->getInnerIterator());
+ $iterator->offsetSet($key, 'alter');
+ var_dump($iterator->getInnerIterator());
+}
+$copy = $iterator->getArrayCopy();
+var_dump($copy);
+?>
+--EXPECTF--
+update 1
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(3) {
+ [1]=>
+ string(4) "val1"
+ [2]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+ [4]=>
+ string(4) "val4"
+ }
+}
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(3) {
+ [1]=>
+ string(5) "alter"
+ [2]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+ [4]=>
+ string(4) "val4"
+ }
+}
+update 2
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+}
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(2) {
+ [2]=>
+ string(5) "alter"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+}
+update 3
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+}
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(1) {
+ [3]=>
+ string(5) "alter"
+ }
+}
+update 4
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(3) {
+ [1]=>
+ string(5) "alter"
+ [2]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+ [4]=>
+ string(4) "val4"
+ }
+}
+object(RecursiveArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(3) {
+ [1]=>
+ string(5) "alter"
+ [2]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+ [4]=>
+ string(5) "alter"
+ }
+}
+array(3) {
+ [1]=>
+ string(5) "alter"
+ [2]=>
+ array(2) {
+ [2]=>
+ string(4) "val2"
+ [3]=>
+ array(1) {
+ [3]=>
+ string(4) "val3"
+ }
+ }
+ [4]=>
+ string(5) "alter"
+}
diff --git a/ext/spl/tests/bug42703.phpt b/ext/spl/tests/bug42703.phpt
new file mode 100644
index 0000000..5c52763
--- /dev/null
+++ b/ext/spl/tests/bug42703.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Bug #42703 (Exception raised in an iterator::current() causes segfault in FilterIterator)
+--FILE--
+<?php
+class BlaIterator implements Iterator
+{
+ public function rewind() { }
+
+ public function next() { }
+
+ public function valid() {
+ return true;
+ }
+
+ public function current()
+ {
+ throw new Exception('boo');
+ }
+
+ public function key() { }
+}
+
+$it = new BlaIterator();
+$itit = new IteratorIterator($it);
+
+try {
+ foreach($itit as $key => $value) {
+ echo $key, $value;
+ }
+}
+catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+var_dump($itit->current());
+var_dump($itit->key());
+?>
+--EXPECTF--
+string(3) "boo"
+NULL
+NULL
diff --git a/ext/spl/tests/bug44144.phpt b/ext/spl/tests/bug44144.phpt
new file mode 100644
index 0000000..2933d2f
--- /dev/null
+++ b/ext/spl/tests/bug44144.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #44144 (spl_autoload_functions() should return object instance when appropriate)
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+class Foo {
+ public function nonstaticMethod() {}
+}
+$foo = new Foo;
+spl_autoload_register(array($foo, 'nonstaticMethod'));
+$funcs = spl_autoload_functions();
+var_dump($funcs);
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ object(Foo)#%d (0) {
+ }
+ [1]=>
+ string(15) "nonstaticMethod"
+ }
+}
+
+
diff --git a/ext/spl/tests/bug44615.phpt b/ext/spl/tests/bug44615.phpt
new file mode 100644
index 0000000..1fd3d19
--- /dev/null
+++ b/ext/spl/tests/bug44615.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RecursiveArrayIterator bug 44615
+--CREDITS--
+Julien Pauli <doctorrock83@gmail.com>
+#testfest phpcampparis 2008-06-07
+--FILE--
+<?php
+$a = new stdClass();
+
+$array = array(array('z',$a),array('q','s'));
+
+$rai = new RecursiveArrayIterator($array,RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
+
+foreach (new RecursiveIteratorIterator($rai) as $t) {
+ var_dump($t);
+}
+echo "Second:\n";
+$rai = new RecursiveArrayIterator($array);
+foreach (new RecursiveIteratorIterator($rai) as $t) {
+ var_dump($t);
+}
+?>
+--EXPECTF--
+string(1) "z"
+object(stdClass)#1 (0) {
+}
+string(1) "q"
+string(1) "s"
+Second:
+string(1) "z"
+string(1) "q"
+string(1) "s"
diff --git a/ext/spl/tests/bug45216.phpt b/ext/spl/tests/bug45216.phpt
new file mode 100644
index 0000000..b3c4aa5
--- /dev/null
+++ b/ext/spl/tests/bug45216.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::fgetss (bug 45216)
+--CREDITS--
+Perrick Penet <perrick@noparking.net>
+#testfest phpcampparis 2008-06-07
+--FILE--
+<?php
+$file = dirname(__FILE__) . '/foo.html';
+file_put_contents($file, 'text 0<div class="tested">text 1</div>');
+$handle = fopen($file, 'r');
+
+$object = new SplFileObject($file);
+var_dump($object->fgetss());
+var_dump(fgetss($handle));
+?>
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/foo.html');
+?>
+--EXPECTF--
+string(12) "text 0text 1"
+string(12) "text 0text 1"
diff --git a/ext/spl/tests/bug45614.phpt b/ext/spl/tests/bug45614.phpt
new file mode 100644
index 0000000..8f99934
--- /dev/null
+++ b/ext/spl/tests/bug45614.phpt
@@ -0,0 +1,56 @@
+--TEST--
+SPL: Bug#45614 (ArrayIterator can show 1st private prop of wrapped object)
+--FILE--
+<?php
+class C {
+ private $priv1 = 'secret1';
+ private $priv2 = 'secret2';
+ public $pub1 = 'public1';
+ public $pub2 = 'public2';
+ public $pub3 = 'public3';
+}
+
+function showFirstTwoItems($it) {
+ echo str_replace("\0", '\0', $it->key()) . " => " . $it->current() .
+"\n";
+ $it->next();
+ echo str_replace("\0", '\0', $it->key()) . " => " . $it->current() .
+"\n";
+}
+
+$ao = new ArrayObject(new C);
+$ai = $ao->getIterator();
+
+echo "--> Show the first two items:\n";
+showFirstTwoItems($ai);
+
+echo "\n--> Rewind and show the first two items:\n";
+$ai->rewind();
+showFirstTwoItems($ai);
+
+echo "\n--> Invalidate current position and show the first two items:\n";
+unset($ai[$ai->key()]);
+$ai->current();
+showFirstTwoItems($ai);
+
+echo "\n--> Rewind, seek and show the first two items:\n";
+$ai->rewind();
+$ai->seek(0);
+showFirstTwoItems($ai);
+?>
+--EXPECT--
+--> Show the first two items:
+pub1 => public1
+pub2 => public2
+
+--> Rewind and show the first two items:
+pub1 => public1
+pub2 => public2
+
+--> Invalidate current position and show the first two items:
+pub1 => public1
+pub3 => public3
+
+--> Rewind, seek and show the first two items:
+pub1 => public1
+pub3 => public3
diff --git a/ext/spl/tests/bug45622.phpt b/ext/spl/tests/bug45622.phpt
new file mode 100644
index 0000000..a8fe2c4
--- /dev/null
+++ b/ext/spl/tests/bug45622.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: Bug #45622 (isset($arrayObject->p) misbehaves with ArrayObject::ARRAY_AS_PROPS set
+--FILE--
+<?php
+
+class C extends ArrayObject {
+ public $p = 'object property';
+}
+
+$ao = new C(array('p'=>'array element'));
+$ao->setFlags(ArrayObject::ARRAY_AS_PROPS);
+
+echo "\n--> Access the real property:\n";
+var_dump(isset($ao->p));
+var_dump($ao->p);
+
+echo "\n--> Remove the real property and access the array element:\n";
+unset($ao->p);
+var_dump(isset($ao->p));
+var_dump($ao->p);
+
+echo "\n--> Remove the array element and try access again:\n";
+unset($ao->p);
+var_dump(isset($ao->p));
+var_dump($ao->p);
+
+echo "\n--> Re-add the real property:\n";
+$ao->p = 'object property';
+var_dump(isset($ao->p));
+var_dump($ao->p);
+?>
+--EXPECTF--
+
+--> Access the real property:
+bool(true)
+%unicode|string%(15) "object property"
+
+--> Remove the real property and access the array element:
+bool(true)
+%unicode|string%(13) "array element"
+
+--> Remove the array element and try access again:
+bool(false)
+
+Notice: Undefined index: p in %s on line %d
+NULL
+
+--> Re-add the real property:
+bool(true)
+%unicode|string%(15) "object property"
+
diff --git a/ext/spl/tests/bug45622b.phpt b/ext/spl/tests/bug45622b.phpt
new file mode 100644
index 0000000..f101a84
--- /dev/null
+++ b/ext/spl/tests/bug45622b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Ensure fix to bug45622 doesn't cause __isset() to be called when ArrayObject::ARRAY_AS_PROPS is used.
+--FILE--
+<?php
+class UsesMagic extends ArrayObject {
+ function __get($n) { echo "In " . __METHOD__ . "!\n"; }
+ function __set($n, $v) { echo "In " . __METHOD__ . "!\n"; }
+ function __isset($n) { echo "In " . __METHOD__ . "!\n"; }
+ function __unset($n) { echo "In " . __METHOD__ . "!\n"; }
+}
+$ao = new UsesMagic(array(), ArrayObject::ARRAY_AS_PROPS);
+
+echo "Doesn't trigger __get.\n";
+echo $ao->prop1;
+
+echo "Doesn't trigger __set.\n";
+$ao->prop2 = 'foo';
+
+echo "Doesn't trigger __unset.\n";
+unset($ao->prop3);
+
+echo "Shouldn't trigger __isset.\n";
+isset($ao->prop4);
+?>
+--EXPECTF--
+Doesn't trigger __get.
+
+Notice: Undefined index: prop1 in %s on line 11
+Doesn't trigger __set.
+Doesn't trigger __unset.
+
+Notice: Undefined index: prop3 in %s on line 17
+Shouldn't trigger __isset. \ No newline at end of file
diff --git a/ext/spl/tests/bug45826.phpt b/ext/spl/tests/bug45826.phpt
new file mode 100644
index 0000000..7993bfa
--- /dev/null
+++ b/ext/spl/tests/bug45826.phpt
@@ -0,0 +1,88 @@
+--TEST--
+ArrayObject/ArrayIterator : serialization
+--FILE--
+<?php
+$o = new ArrayObject();
+$y = new StdClass;
+$o->append($y);
+$o->append($y);
+$o->append($o);
+
+var_dump($o[0] === $o[1]);
+var_dump($o[2] === $o);
+
+$s1 = serialize($o);
+$s2 = $o->serialize();
+var_dump($s1);
+var_dump($s2);
+
+$o1 =unserialize($s1);
+
+var_dump($o1[0] === $o1[1]);
+var_dump($o1[2] === $o1);
+
+$o2 = new ArrayObject();
+$o2->unserialize($s2);
+
+var_dump($o2[0] === $o2[1]);
+var_dump($o2[2] !== $o2);
+var_dump($o2[2][2] === $o2[2]);
+
+echo "#### Extending ArrayObject\n";
+unset($o,$x,$s1,$s2,$o1,$o2);
+class ArrayObject2 extends ArrayObject {
+ public function serialize() {
+ return parent::serialize();
+ }
+
+ public function unserialize($s) {
+ return parent::unserialize($s);
+ }
+}
+
+$o = new ArrayObject2();
+$y = new StdClass;
+$o->append($y);
+$o->append($y);
+$o->append($o);
+
+var_dump($o[0] === $o[1]);
+var_dump($o[2] === $o);
+
+$s1 = serialize($o);
+$s2 = $o->serialize();
+var_dump($s1);
+var_dump($s2);
+
+$o1 =unserialize($s1);
+
+var_dump($o1[0] === $o1[1]);
+var_dump($o1[2] === $o1);
+
+$o2 = new ArrayObject2();
+$o2->unserialize($s2);
+
+var_dump($o2[0] === $o2[1]);
+var_dump($o2[2] !== $o2);
+var_dump($o2[2][2] === $o2[2]);
+?>
+--EXPECT--
+bool(true)
+bool(true)
+string(84) "C:11:"ArrayObject":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}"
+string(125) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:11:"ArrayObject":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}"
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+#### Extending ArrayObject
+bool(true)
+bool(true)
+string(85) "C:12:"ArrayObject2":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}"
+string(126) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:12:"ArrayObject2":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}"
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/spl/tests/bug46031.phpt b/ext/spl/tests/bug46031.phpt
new file mode 100644
index 0000000..9261ff0
--- /dev/null
+++ b/ext/spl/tests/bug46031.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Bug #46031 (Segfault in AppendIterator::next)
+--FILE--
+<?php
+$x = new AppendIterator();
+var_dump($x->next());
+?>
+--EXPECT--
+NULL
diff --git a/ext/spl/tests/bug46051.phpt b/ext/spl/tests/bug46051.phpt
new file mode 100644
index 0000000..49a5824
--- /dev/null
+++ b/ext/spl/tests/bug46051.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #46051 (SplFileInfo::openFile - memory overlap)
+--FILE--
+<?php
+
+$x = new splfileinfo(__FILE__);
+
+try {
+$x->openFile(NULL, NULL, NULL);
+} catch (Exception $e) { }
+
+var_dump($x->getPathName());
+--EXPECTF--
+%unicode|string%(%d) "%sbug46051.php"
diff --git a/ext/spl/tests/bug46053.phpt b/ext/spl/tests/bug46053.phpt
new file mode 100644
index 0000000..75da7f3
--- /dev/null
+++ b/ext/spl/tests/bug46053.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #46053 (SplFileObject::seek - Endless loop)
+--FILE--
+<?php
+
+$x = new splfileobject(__FILE__);
+$x->getPathName();
+$x->seek(10);
+$x->seek(0);
+var_dump(trim($x->fgets()));
+--EXPECTF--
+string(%d) "<?php"
diff --git a/ext/spl/tests/bug46088.phpt b/ext/spl/tests/bug46088.phpt
new file mode 100644
index 0000000..4785377
--- /dev/null
+++ b/ext/spl/tests/bug46088.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug #46088 (RegexIterator::accept - segfault)
+--FILE--
+<?php
+
+$x = new RegexIterator(new ArrayIterator(range(1, 10)), '/\d/');
+var_dump($x->accept());
+
+?>
+--EXPECT--
+bool(false)
diff --git a/ext/spl/tests/bug46115.phpt b/ext/spl/tests/bug46115.phpt
new file mode 100644
index 0000000..71207d8
--- /dev/null
+++ b/ext/spl/tests/bug46115.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug #46115 (Memory leak when calling a method using Reflection)
+--FILE--
+<?php
+$h = new RecursiveArrayIterator(array());
+$x = new reflectionmethod('RecursiveArrayIterator', 'asort');
+$z = $x->invoke($h);
+?>
+DONE
+--EXPECT--
+DONE
diff --git a/ext/spl/tests/bug46160.phpt b/ext/spl/tests/bug46160.phpt
new file mode 100644
index 0000000..e4dbdff
--- /dev/null
+++ b/ext/spl/tests/bug46160.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #46160 (SPL - Memory leak when exception is throwed in offsetSet method)
+--FILE--
+<?php
+
+try {
+ $x = new splqueue;
+ $x->offsetSet(0, 0);
+} catch (Exception $e) { }
+
+?>
+DONE
+--EXPECT--
+DONE
diff --git a/ext/spl/tests/bug47534.phpt b/ext/spl/tests/bug47534.phpt
new file mode 100644
index 0000000..d221c23
--- /dev/null
+++ b/ext/spl/tests/bug47534.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: RecursiveDirectoryIterator bug 47534
+--FILE--
+<?php
+$it1 = new RecursiveDirectoryIterator(dirname(__FILE__), FileSystemIterator::CURRENT_AS_PATHNAME);
+$it1->rewind();
+echo gettype($it1->current())."\n";
+
+$it2 = new RecursiveDirectoryIterator(dirname(__FILE__));
+$it2->rewind();
+echo gettype($it2->current())."\n";
+--EXPECT--
+string
+object
diff --git a/ext/spl/tests/bug48023.phpt b/ext/spl/tests/bug48023.phpt
new file mode 100644
index 0000000..ed0ff9e
--- /dev/null
+++ b/ext/spl/tests/bug48023.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #48023 (spl_autoload_register didn't addref closures)
+--FILE--
+<?php
+spl_autoload_register(function(){});
+
+new Foo;
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Class 'Foo' not found in %s on line %d
diff --git a/ext/spl/tests/bug48361.phpt b/ext/spl/tests/bug48361.phpt
new file mode 100644
index 0000000..44b05ab
--- /dev/null
+++ b/ext/spl/tests/bug48361.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: Bug #48361 SpleFileInfo::getPathName should return the dirname's path
+--FILE--
+<?php
+$info = new SplFileInfo(__FILE__);
+var_dump($info->getRealPath());
+var_dump($info->getPathInfo()->getRealPath());
+?>
+===DONE===
+--EXPECTF--
+string(%d) "%stests%sbug48361.php"
+string(%d) "%stests"
+===DONE===
+
diff --git a/ext/spl/tests/bug48493.phpt b/ext/spl/tests/bug48493.phpt
new file mode 100644
index 0000000..d0be7f8
--- /dev/null
+++ b/ext/spl/tests/bug48493.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: Bug #48493 spl_autoload_unregister() can't handle prepended functions
+--FILE--
+<?php
+function autoload1() {}
+
+function autoload2() {}
+
+spl_autoload_register('autoload2');
+spl_autoload_register('autoload1', true, true);
+var_dump(spl_autoload_functions());
+
+spl_autoload_unregister('autoload2');
+var_dump(spl_autoload_functions());
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(9) "autoload1"
+ [1]=>
+ string(9) "autoload2"
+}
+array(1) {
+ [0]=>
+ string(9) "autoload1"
+}
diff --git a/ext/spl/tests/bug49263.phpt b/ext/spl/tests/bug49263.phpt
new file mode 100644
index 0000000..2075577
--- /dev/null
+++ b/ext/spl/tests/bug49263.phpt
@@ -0,0 +1,54 @@
+--TEST--
+SPL: SplObjectStorage serialization references
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+$o1 = new stdClass;
+$o2 = new stdClass;
+
+$s = new splObjectStorage();
+
+$s->attach($o1, array('prev' => 2, 'next' => $o2));
+$s->attach($o2, array('prev' => $o1));
+
+$ss = serialize($s);
+unset($s,$o1,$o2);
+echo $ss."\n";
+var_dump(unserialize($ss));
+?>
+===DONE===
+--EXPECTF--
+C:16:"SplObjectStorage":113:{x:i:2;O:8:"stdClass":0:{},a:2:{s:4:"prev";i:2;s:4:"next";O:8:"stdClass":0:{}};r:6;,a:1:{s:4:"prev";r:3;};m:a:0:{}}
+object(SplObjectStorage)#2 (1) {
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#1 (0) {
+ }
+ ["inf"]=>
+ array(2) {
+ ["prev"]=>
+ int(2)
+ ["next"]=>
+ object(stdClass)#3 (0) {
+ }
+ }
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(stdClass)#3 (0) {
+ }
+ ["inf"]=>
+ array(1) {
+ ["prev"]=>
+ object(stdClass)#1 (0) {
+ }
+ }
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/bug49723.phpt b/ext/spl/tests/bug49723.phpt
new file mode 100644
index 0000000..221e806
--- /dev/null
+++ b/ext/spl/tests/bug49723.phpt
@@ -0,0 +1,16 @@
+--TEST--
+LimitIterator: do not seek if not needed
+--FILE--
+<?php
+
+$it = new ArrayIterator(array());
+
+$lit = new LimitIterator($it, 0, 5);
+
+foreach ($lit as $v) {
+ echo $v;
+}
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/ext/spl/tests/bug49972.phpt b/ext/spl/tests/bug49972.phpt
new file mode 100644
index 0000000..843c251
--- /dev/null
+++ b/ext/spl/tests/bug49972.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug #49972 (AppendIterator undefined function crash)
+--FILE--
+<?php
+
+$iterator = new AppendIterator();
+$iterator->undefined();
+
+?>
+--EXPECTF--
+Fatal error: Call to undefined method AppendIterator::undefined() in %s on line %d
diff --git a/ext/spl/tests/bug50579.phpt b/ext/spl/tests/bug50579.phpt
new file mode 100644
index 0000000..e32262a
--- /dev/null
+++ b/ext/spl/tests/bug50579.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #50579 (RegexIterator::REPLACE doesn't work)
+--FILE--
+<?php
+
+class foo extends ArrayIterator {
+ public function __construct( ) {
+ parent::__construct(array(
+ 'test1'=>'test888',
+ 'test2'=>'what?',
+ 'test3'=>'test999'));
+ }
+}
+$h = new foo;
+$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE);
+$i->replacement = '[$0]';
+foreach ($i as $name=>$value) {
+ echo $name . '=>' . $value . "\n";
+}
+
+$i->replacement = '$1';
+foreach ($i as $name=>$value) {
+ echo $name . '=>' . $value . "\n";
+}
+
+$h = new foo;
+$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE);
+$i->replacement = '[$1]';
+foreach ($i as $name=>$value) {
+ echo $name . '=>' . $value . "\n";
+}
+
+?>
+--EXPECTF--
+test1=>[test888]
+test3=>[test999]
+test1=>888
+test3=>999
+test1=>[888]
+test3=>[999]
diff --git a/ext/spl/tests/bug51119.phpt b/ext/spl/tests/bug51119.phpt
new file mode 100644
index 0000000..441aa12
--- /dev/null
+++ b/ext/spl/tests/bug51119.phpt
@@ -0,0 +1,34 @@
+--TEST--
+SPL: LimitIterator zero is valid offset
+--FILE--
+<?php
+
+$array = array('a', 'b', 'c');
+$arrayIterator = new ArrayIterator($array);
+
+try {
+ $limitIterator = new LimitIterator($arrayIterator, 0);
+ foreach ($limitIterator as $item) {
+ echo $item . "\n";
+ }
+} catch (OutOfRangeException $e){
+ print $e->getMessage() . "\n";
+}
+
+try {
+ $limitIterator = new LimitIterator($arrayIterator, -1);
+ foreach ($limitIterator as $item) {
+ echo $item . "\n";
+ }
+} catch (OutOfRangeException $e){
+ print $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+a
+b
+c
+Parameter offset must be >= 0
+===DONE===
diff --git a/ext/spl/tests/bug51374.phpt b/ext/spl/tests/bug51374.phpt
new file mode 100644
index 0000000..a4d2853
--- /dev/null
+++ b/ext/spl/tests/bug51374.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplFileObject wrongly initializes objects
+--FILE--
+<?php
+class Foo extends SplFileObject
+{
+ public $bam = array();
+}
+$fileInfo = new SplFileInfo('php://temp');
+$fileInfo->setFileClass('Foo');
+$file = $fileInfo->openFile('r');
+
+print var_dump($file->bam); // is null or UNKNOWN:0
+?>
+===DONE===
+--EXPECT--
+array(0) {
+}
+===DONE===
diff --git a/ext/spl/tests/bug51532.phpt b/ext/spl/tests/bug51532.phpt
new file mode 100644
index 0000000..3a0722b
--- /dev/null
+++ b/ext/spl/tests/bug51532.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: Allow valid extension of SplFileObject::fscanf
+--FILE--
+<?php
+
+class A extends SplFileObject {
+ public function fscanf($format) {
+
+ }
+}
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/ext/spl/tests/bug52238.phpt b/ext/spl/tests/bug52238.phpt
new file mode 100644
index 0000000..10da0b5
--- /dev/null
+++ b/ext/spl/tests/bug52238.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #52238 - Crash when an Exception occurred in iterator_to_array
+--FILE--
+<?php
+class Foo implements IteratorAggregate
+{
+ public function bar() {
+ throw new Exception;
+ }
+
+ public function getIterator() {
+ return new ArrayIterator($this->bar());
+ }
+}
+var_dump(iterator_to_array(new Foo));
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 %s: Foo->bar()
+#1 [internal function]: Foo->getIterator()
+#2 %s: iterator_to_array(Object(Foo))
+#3 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/bug52573.phpt b/ext/spl/tests/bug52573.phpt
new file mode 100644
index 0000000..54587fa
--- /dev/null
+++ b/ext/spl/tests/bug52573.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #52573 (SplFileObject::fscanf Segmentation fault)
+--FILE--
+<?php // test
+
+$result = null;
+$f = new SplFileObject(__FILE__, 'r');
+var_dump($f->fscanf('<?php // %s', $result));
+var_dump($result);
+var_dump($f->fscanf('<?php // %s'));
+?>
+--EXPECTF--
+int(1)
+string(4) "test"
+array(1) {
+ [0]=>
+ NULL
+}
diff --git a/ext/spl/tests/bug52861.phpt b/ext/spl/tests/bug52861.phpt
new file mode 100644
index 0000000..30a3261
--- /dev/null
+++ b/ext/spl/tests/bug52861.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #52861 (unset failes with ArrayObject and deep arrays)
+--FILE--
+<?php
+$arrayObject = new ArrayObject(array('foo' => array('bar' => array('baz' => 'boo'))));
+
+unset($arrayObject['foo']['bar']['baz']);
+print_r($arrayObject->getArrayCopy());
+?>
+--EXPECT--
+Array
+(
+ [foo] => Array
+ (
+ [bar] => Array
+ (
+ )
+
+ )
+
+)
+
diff --git a/ext/spl/tests/bug53071.phpt b/ext/spl/tests/bug53071.phpt
new file mode 100644
index 0000000..c2c2605
--- /dev/null
+++ b/ext/spl/tests/bug53071.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #53071 (Usage of SPLObjectStorage defeats gc_collect_cycles)
+--FILE--
+<?php
+gc_enable();
+class myClass
+{
+ public $member;
+}
+function LimitedScope()
+{
+ $myA = new myClass();
+ $myB = new SplObjectStorage();
+ $myC = new myClass();
+ $myC->member = $myA; // myC has a referece to myA
+ $myB->Attach($myC); // myB attaches myC
+ $myA->member = $myB; // myA has myB, comleting the cycle
+}
+LimitedScope();
+var_dump(gc_collect_cycles());
+
+echo "Done.\n";
+
+?>
+--EXPECTF--
+int(5)
+Done.
diff --git a/ext/spl/tests/bug53144.phpt b/ext/spl/tests/bug53144.phpt
new file mode 100644
index 0000000..7cf179b
--- /dev/null
+++ b/ext/spl/tests/bug53144.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #53144 (Segfault in SplObjectStorage::removeAll)
+--FILE--
+<?php
+
+$o1 = new StdClass;
+$o2 = new StdClass;
+
+$b = new SplObjectStorage();
+$b[$o1] = "bar";
+$b[$o2] = "baz";
+
+var_dump(count($b));
+$b->removeAll($b);
+var_dump(count($b));
+
+?>
+--EXPECTF--
+int(2)
+int(0) \ No newline at end of file
diff --git a/ext/spl/tests/bug53362.phpt b/ext/spl/tests/bug53362.phpt
new file mode 100644
index 0000000..70ba6e2
--- /dev/null
+++ b/ext/spl/tests/bug53362.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #53362 (Segmentation fault when extending SplFixedArray)
+--FILE--
+<?php
+
+class obj extends SplFixedArray{
+ public function offsetSet($offset, $value) {
+ var_dump($offset);
+ }
+}
+
+$obj = new obj;
+
+$obj[]=2;
+$obj[]=2;
+$obj[]=2;
+
+?>
+--EXPECTF--
+NULL
+NULL
+NULL
diff --git a/ext/spl/tests/bug53515.phpt b/ext/spl/tests/bug53515.phpt
new file mode 100644
index 0000000..8ecb02b
--- /dev/null
+++ b/ext/spl/tests/bug53515.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #53515 (property_exists incorrect on ArrayObject null and 0 values)
+--FILE--
+<?php
+
+$a = array('a' => 1, 'b'=> true, 'c' => 0, 'd' => null, 'e' => false, 'f' => array());
+$o = new ArrayObject($a, ArrayObject::ARRAY_AS_PROPS);
+
+$a['z'] = '';
+$a[''] = '';
+
+foreach ($a as $key => $value) {
+ echo $key . ': ' . (is_null($value) ? 'null' : @"$value") .
+ ' array_key_exists: ' . (array_key_exists($key, $a) ? 'true' : 'false') .
+ ' property_exists: ' . (property_exists($o, $key) ? 'true' : 'false'),"\n";
+}
+
+?>
+--EXPECT--
+a: 1 array_key_exists: true property_exists: true
+b: 1 array_key_exists: true property_exists: true
+c: 0 array_key_exists: true property_exists: true
+d: null array_key_exists: true property_exists: true
+e: array_key_exists: true property_exists: true
+f: Array array_key_exists: true property_exists: true
+z: array_key_exists: true property_exists: false
+: array_key_exists: true property_exists: false
diff --git a/ext/spl/tests/bug54281.phpt b/ext/spl/tests/bug54281.phpt
new file mode 100644
index 0000000..d42d9e5
--- /dev/null
+++ b/ext/spl/tests/bug54281.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #54281 (Crash in spl_recursive_it_rewind_ex)
+--FILE--
+<?php
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator {
+ function __construct($it, $max_depth) { }
+}
+$it = new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array()), 2);
+
+foreach($it as $k=>$v) { }
+
+?>
+--EXPECTF--
+Fatal error: RecursiveIteratorIterator::rewind(): The RecursiveArrayIteratorIterator instance wasn't initialized properly in %s on line %d
diff --git a/ext/spl/tests/bug54291.phpt b/ext/spl/tests/bug54291.phpt
new file mode 100644
index 0000000..b8f596e
--- /dev/null
+++ b/ext/spl/tests/bug54291.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Bug #54291 (Crash iterating DirectoryIterator for dir name starting with \0)
+--FILE--
+<?php
+$dir = new DirectoryIterator("\x00/abc");
+$dir->isFile();
+--EXPECTF--
+Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Failed to open directory ""' in %s:%d
+Stack trace:
+#0 %s(%d): DirectoryIterator->__construct('?/abc')
+#1 {main}
+ thrown in %s on line %d
+
diff --git a/ext/spl/tests/bug54292.phpt b/ext/spl/tests/bug54292.phpt
new file mode 100644
index 0000000..d9175f7
--- /dev/null
+++ b/ext/spl/tests/bug54292.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #54292 (Wrong parameter causes crash in SplFileObject::__construct())
+--FILE--
+<?php
+
+try {
+ new SplFileObject('foo', array());
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+?>
+--EXPECTF--
+string(74) "SplFileObject::__construct() expects parameter 2 to be string, array given"
diff --git a/ext/spl/tests/bug54304.phpt b/ext/spl/tests/bug54304.phpt
new file mode 100644
index 0000000..32cbe48
--- /dev/null
+++ b/ext/spl/tests/bug54304.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Bug #54304 (Setting replacement value for RegexIterator doesn't work)
+--FILE--
+<?php
+class foo extends ArrayIterator {
+ public function __construct( ) {
+ parent::__construct(array(
+ 'test3'=>'test999'));
+ }
+}
+
+$h = new foo;
+$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE);
+$i->replacement = 42;
+var_dump($i->replacement);
+foreach ($i as $name=>$value) {
+ var_dump($name, $value);
+}
+var_dump($i->replacement);
+?>
+--EXPECT--
+int(42)
+string(5) "test3"
+string(2) "42"
+int(42)
+
diff --git a/ext/spl/tests/bug54323.phpt b/ext/spl/tests/bug54323.phpt
new file mode 100644
index 0000000..df6416a
--- /dev/null
+++ b/ext/spl/tests/bug54323.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #54323 (Accessing unset()'ed ArrayObject's property causes crash)
+--FILE--
+<?php
+class C {
+ public $prop = 'C::prop.orig';
+}
+class MyArrayObject extends ArrayObject {
+}
+$c = new C;
+$ao = new MyArrayObject($c);
+testAccess($c, $ao);
+function testAccess($c, $ao) {
+ foreach ($ao as $key=>$value) {
+ }
+ unset($ao['prop']);
+ var_dump($c->prop, $ao['prop']);
+}
+--EXPECTF--
+Notice: Undefined property: C::$prop in %sbug54323.php on line 14
+
+Notice: Undefined index: prop in %sbug54323.php on line 14
+NULL
+NULL
diff --git a/ext/spl/tests/bug54384.phpt b/ext/spl/tests/bug54384.phpt
new file mode 100644
index 0000000..a1ce7ed
--- /dev/null
+++ b/ext/spl/tests/bug54384.phpt
@@ -0,0 +1,171 @@
+--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();
+} );
+
+echo "AppendIterator... ";
+class AppendIteratorTest extends AppendIterator {
+ function __construct(){}
+}
+test ( function() {
+$o = new AppendIteratorTest;
+foreach ($o as $a) {
+echo $a,"\n";
+}
+} );
+
+echo "InfiniteIterator... ";
+class InfiniteIteratorTest extends InfiniteIterator {
+ function __construct(){}
+}
+test ( function() {
+$o = new InfiniteIteratorTest;
+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)
+AppendIterator... exception (expected)
+InfiniteIterator... exception (expected)
diff --git a/ext/spl/tests/bug54970.phpt b/ext/spl/tests/bug54970.phpt
new file mode 100644
index 0000000..62b1eed
--- /dev/null
+++ b/ext/spl/tests/bug54970.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Bug #54970 (SplFixedArray::setSize() isn't resizing)
+--FILE--
+<?php
+
+$fa = new SplFixedArray(2);
+$fa[0] = 'Hello';
+$fa[1] = 'World';
+$fa->setSize(3);
+$fa[2] = '!';
+var_dump($fa);
+$fa->setSize(2);
+var_dump($fa);
+var_dump($fa->getSize());
+
+
+?>
+--EXPECTF--
+object(SplFixedArray)#%d (3) {
+ [0]=>
+ string(5) "Hello"
+ [1]=>
+ string(5) "World"
+ [2]=>
+ string(1) "!"
+}
+object(SplFixedArray)#%d (2) {
+ [0]=>
+ string(5) "Hello"
+ [1]=>
+ string(5) "World"
+}
+int(2)
diff --git a/ext/spl/tests/bug54971.phpt b/ext/spl/tests/bug54971.phpt
new file mode 100644
index 0000000..22cdfba
--- /dev/null
+++ b/ext/spl/tests/bug54971.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug #54971 (Wrong result when using iterator_to_array with use_keys on true)
+--SKIPIF--
+<?php
+if (!extension_loaded('dom')) die("skip this test needs --enable-dom");
+?>
+--FILE--
+<?php
+
+$source = <<<XML
+<root>
+<node>val1</node>
+<node>val2</node>
+</root>
+XML;
+
+
+$doc = new DOMDocument();
+$doc->loadXML($source);
+
+$xpath = new DOMXPath($doc);
+$items = $xpath->query('//node');
+
+print_r(array_map('get_class', iterator_to_array($items, false)));
+print_r(array_map('get_class', iterator_to_array($items, true)));
+?>
+--EXPECT--
+Array
+(
+ [0] => DOMElement
+ [1] => DOMElement
+)
+Array
+(
+ [0] => DOMElement
+ [1] => DOMElement
+)
diff --git a/ext/spl/tests/bug60201.phpt b/ext/spl/tests/bug60201.phpt
new file mode 100644
index 0000000..68a5daa
--- /dev/null
+++ b/ext/spl/tests/bug60201.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #60201 (SplFileObject::setCsvControl does not expose third argument via Reflection)
+--FILE--
+<?php
+
+$method = new ReflectionMethod('SplFileObject', 'setCsvControl');
+$params = $method->getParameters();
+var_dump($params);
+
+?>
+===DONE===
+--EXPECTF--
+array(3) {
+ [0]=>
+ &object(ReflectionParameter)#%d (1) {
+ ["name"]=>
+ string(9) "delimiter"
+ }
+ [1]=>
+ &object(ReflectionParameter)#%d (1) {
+ ["name"]=>
+ string(9) "enclosure"
+ }
+ [2]=>
+ &object(ReflectionParameter)#%d (1) {
+ ["name"]=>
+ string(6) "escape"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/bug61326.phpt b/ext/spl/tests/bug61326.phpt
new file mode 100644
index 0000000..85b5779
--- /dev/null
+++ b/ext/spl/tests/bug61326.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #61326: ArrayObject comparison
+--FILE--
+<?php
+$aobj1 = new ArrayObject(array(0));
+$aobj2 = new ArrayObject(array(1));
+var_dump($aobj1 == $aobj2);
+
+$aobj3 = new ArrayObject(array(0));
+var_dump($aobj1 == $aobj3);
+
+$aobj3->foo = 'bar';
+var_dump($aobj1 == $aobj3);
+--EXPECT--
+bool(false)
+bool(true)
+bool(false)
diff --git a/ext/spl/tests/bug61347.phpt b/ext/spl/tests/bug61347.phpt
new file mode 100644
index 0000000..cb09185
--- /dev/null
+++ b/ext/spl/tests/bug61347.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #61347 (inconsist isset behavior of Arrayobject)
+--FILE--
+<?php
+$a = array('b' => NULL, 37 => NULL);
+var_dump(isset($a['b'])); //false
+
+$b = new ArrayObject($a);
+var_dump(isset($b['b'])); //false
+var_dump(isset($b[37])); //false
+var_dump(isset($b['no_exists'])); //false
+var_dump(empty($b['b'])); //true
+var_dump(empty($b[37])); //true
+
+var_dump(array_key_exists('b', $b)); //true
+var_dump($b['b']);
+
+$a = array('b' => '', 37 => false);
+$b = new ArrayObject($a);
+var_dump(isset($b['b'])); //true
+var_dump(isset($b[37])); //true
+var_dump(isset($b['no_exists'])); //false
+var_dump(empty($b['b'])); //true
+var_dump(empty($b[37])); //true
+
+
+--EXPECT--
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+NULL
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
diff --git a/ext/spl/tests/bug61418.phpt b/ext/spl/tests/bug61418.phpt
new file mode 100644
index 0000000..c5d9db9
--- /dev/null
+++ b/ext/spl/tests/bug61418.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Bug #61418: Segmentation fault using FiltesystemIterator & RegexIterator
+--FILE--
+<?php
+$fileIterator = new FilesystemIterator(__DIR__, FilesystemIterator::KEY_AS_FILENAME);
+$regexpIterator = new RegexIterator($fileIterator, '#.*#');
+foreach ($fileIterator as $key => $file)
+{
+}
+unset($regexpIterator);
+unset($fileIterator);
+
+$dirIterator = new DirectoryIterator(__DIR__);
+$regexpIterator2 = new RegexIterator($dirIterator, '#.*#');
+foreach ($dirIterator as $key => $file)
+{
+}
+unset($regexpIterator2);
+unset($dirIterator);
+?>
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/ext/spl/tests/bug61453.phpt b/ext/spl/tests/bug61453.phpt
new file mode 100644
index 0000000..e5b1387
--- /dev/null
+++ b/ext/spl/tests/bug61453.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #61453: SplObjectStorage does not identify objects correctly
+--FILE--
+<?php
+$limit = 1000;
+$objects = new SplObjectStorage;
+for($i = 0; $i < $limit; $i++){
+ $object = new StdClass;
+
+ if(isset($objects[$object])){
+ die("this should never happen, but did after $i iteration");
+ }
+
+ $objects[$object] = 1;
+}
+?>
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/ext/spl/tests/bug61527.phpt b/ext/spl/tests/bug61527.phpt
new file mode 100644
index 0000000..ab13c69
--- /dev/null
+++ b/ext/spl/tests/bug61527.phpt
@@ -0,0 +1,92 @@
+--TEST--
+Bug #61527 (Recursive/ArrayIterator gives misleading notice when array empty or moved to the end)
+--FILE--
+<?php
+$ao = new ArrayObject(array());
+$ai = $ao->getIterator();
+
+/* testing empty array, should no notice at all */
+$ai->next();
+var_dump($ai->key());
+var_dump($ai->current());
+
+/* testing array changing */
+$ao2 = new ArrayObject(array(1 => 1, 2, 3, 4, 5));
+$ai2 = $ao2->getIterator();
+
+$ao2->offsetUnset($ai2->key());
+$ai2->next();
+
+/* now point to 2 */
+$ao2->offsetUnset($ai2->key());
+var_dump($ai2->key());
+
+/* now point to 3 */
+$ao2->offsetUnset($ai2->key());
+var_dump($ai2->current());
+
+$ai2->next();
+var_dump($ai2->key());
+var_dump($ai2->current());
+
+/* should be at the end and no notice */
+$ai2->next();
+var_dump($ai2->key());
+var_dump($ai2->current());
+
+$ai2->rewind();
+$ai2->next();
+$ai2->next();
+/* should reached the end */
+var_dump($ai2->next());
+var_dump($ai2->key());
+
+/* testing RecursiveArrayIterator */
+$ao3 = new ArrayObject(array(), NULL, 'RecursiveArrayIterator');
+$ai3 = $ao3->getIterator();
+
+var_dump($ai3->getChildren());
+
+$ao4 = new ArrayObject(array(1, 2), NULL, 'RecursiveArrayIterator');
+$ai4 = $ao4->getIterator();
+
+$ai4->next();
+$ai4->next();
+$ai4->next();
+var_dump($ai4->hasChildren());
+
+$ai4->rewind();
+$ao4->offsetUnset($ai4->key());
+var_dump($ai4->hasChildren());
+
+$ao4->offsetUnset($ai4->key());
+var_dump($ai4->getChildren());
+?>
+==DONE==
+<?php exit(0); ?>
+--EXPECTF--
+NULL
+NULL
+
+Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d
+
+Notice: ArrayIterator::key(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d
+NULL
+
+Notice: ArrayIterator::current(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d
+NULL
+int(5)
+int(5)
+NULL
+NULL
+NULL
+NULL
+NULL
+bool(false)
+
+Notice: RecursiveArrayIterator::hasChildren(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d
+bool(false)
+
+Notice: RecursiveArrayIterator::getChildren(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d
+NULL
+==DONE==
diff --git a/ext/spl/tests/bug62073.phpt b/ext/spl/tests/bug62073.phpt
new file mode 100644
index 0000000..3bd3553
--- /dev/null
+++ b/ext/spl/tests/bug62073.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #62073 (different ways of iterating over an SplMaxHeap result in different keys)
+--FILE--
+<?php
+$heap = new SplMaxHeap();
+$heap->insert(42);
+foreach ($heap as $key => $value) {
+ var_dump($key);
+ var_dump($value);
+ break;
+}
+
+$heap = new SplMaxHeap();
+$heap->insert(42);
+var_dump($heap->key());
+var_dump($heap->current());
+?>
+--EXPECT--
+int(0)
+int(42)
+int(0)
+int(42)
diff --git a/ext/spl/tests/bug62262.phpt b/ext/spl/tests/bug62262.phpt
new file mode 100644
index 0000000..0e006ec
--- /dev/null
+++ b/ext/spl/tests/bug62262.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Bug #62262: RecursiveArrayIterator does not implement Countable
+--FILE--
+<?php
+
+var_dump(new RecursiveArrayIterator(array()) instanceof Countable);
+
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/spl/tests/bug62328.phpt b/ext/spl/tests/bug62328.phpt
new file mode 100644
index 0000000..33a8aee
--- /dev/null
+++ b/ext/spl/tests/bug62328.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #62328 (cast_object takes precedence over __toString)
+--CREDITS--
+leight at gmail dot com
+--FILE--
+<?php
+
+class SplFileInfo62328 extends SplFileInfo
+{
+ public function __toString()
+ {
+ return '__toString';
+ }
+}
+
+$fi = new SplFileInfo62328(__FILE__);
+
+echo (string)$fi . PHP_EOL;
+echo (string)$fi->__toString() . PHP_EOL;
+
+?>
+--EXPECT--
+__toString
+__toString
diff --git a/ext/spl/tests/bug62433.phpt b/ext/spl/tests/bug62433.phpt
new file mode 100644
index 0000000..bfb3568
--- /dev/null
+++ b/ext/spl/tests/bug62433.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #62433 Inconsistent behavior of RecursiveDirectoryIterator to dot files (. and ..)
+--FILE--
+<?php
+$dots = array_keys(iterator_to_array(new RecursiveDirectoryIterator(__DIR__)));
+$ndots = array_keys(iterator_to_array(new RecursiveDirectoryIterator(__DIR__, FilesystemIterator::SKIP_DOTS)));
+
+var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '.', $dots));
+var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '..', $dots));
+
+var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '.', $ndots));
+var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '..', $ndots));
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
diff --git a/ext/spl/tests/bug62616.phpt b/ext/spl/tests/bug62616.phpt
new file mode 100644
index 0000000..4e4be94
--- /dev/null
+++ b/ext/spl/tests/bug62616.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #62616 (ArrayIterator::count() from IteratorIterator instance gives Segmentation fault)
+--FILE--
+<?php
+$ai = new ArrayIterator(array(0,1));
+
+var_dump($ai->count());
+
+$ii = new IteratorIterator($ai);
+
+var_dump($ii->count());
+?>
+--EXPECTF--
+int(2)
+int(2)
diff --git a/ext/spl/tests/bug62904.phpt b/ext/spl/tests/bug62904.phpt
new file mode 100644
index 0000000..7e392da
--- /dev/null
+++ b/ext/spl/tests/bug62904.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #62904 (Crash when cloning an object which inherits SplFixedArray)
+--FILE--
+<?php
+
+class foo extends SplFixedArray {
+ public function __construct($size) {
+ }
+}
+
+$x = new foo(2);
+
+try {
+ $z = clone $x;
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+--EXPECTF--
+string(40) "The instance wasn't initialized properly"
diff --git a/ext/spl/tests/bug62978.phpt b/ext/spl/tests/bug62978.phpt
new file mode 100644
index 0000000..0d91609
--- /dev/null
+++ b/ext/spl/tests/bug62978.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Bug #62987 (Assigning to ArrayObject[null][something] overrides all undefined variables)
+--FILE--
+<?php
+$a = new ArrayObject();
+
+$b = array();
+
+$a[null]['hurr'] = 'durr';
+
+var_dump($a['epic_magic']);
+var_dump($b['epic_magic']);
+var_dump($c['epic_magic']); // Undefined var!!
+
+$d = array();
+var_dump($a['epic_magic']); // more magic!
+var_dump($d['epic_magic']);
+
+$e = 'srsly?';
+var_dump($a['epic_magic']); // srsly.
+var_dump(isset($a['epic_magic']));
+
+$fp = fopen(__FILE__, 'r');
+var_dump($a[$fp]);
+
+fclose($fp);
+--EXPECTF--
+Notice: Undefined index: epic_magic in %sbug62978.php on line %d
+NULL
+
+Notice: Undefined index: epic_magic in %sbug62978.php on line %d
+NULL
+
+Notice: Undefined variable: c in %sbug62978.php on line %d
+NULL
+
+Notice: Undefined index: epic_magic in %sbug62978.php on line %d
+NULL
+
+Notice: Undefined index: epic_magic in %sbug62978.php on line %d
+NULL
+
+Notice: Undefined index: epic_magic in %sbug62978.php on line %d
+NULL
+bool(false)
+
+Strict Standards: Resource ID#%d used as offset, casting to integer (%d) in %sbug62978.php on line %d
+
+Notice: Undefined offset: %d in %sbug62978.php on line %d
+NULL
diff --git a/ext/spl/tests/bug63680.phpt b/ext/spl/tests/bug63680.phpt
new file mode 100644
index 0000000..3a20c4b
--- /dev/null
+++ b/ext/spl/tests/bug63680.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #63680 (Memleak in splfixedarray with cycle reference)
+--FILE--
+<?php
+function dummy() {
+ $a = new SplFixedArray(1);
+ $b = new SplFixedArray(1);
+ $a[0] = $b;
+ $b[0] = $a;
+}
+
+dummy();
+var_dump(gc_collect_cycles());
+?>
+--EXPECT--
+int(2)
diff --git a/ext/spl/tests/bug64023.phpt b/ext/spl/tests/bug64023.phpt
new file mode 100644
index 0000000..2c177f9
--- /dev/null
+++ b/ext/spl/tests/bug64023.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #64023: Overloading __toString() in SplFileInfo has no effect
+--FILE--
+<?php
+class A extends \SplFileInfo
+{
+ public function __toString() {return ' -expected- ';}
+}
+
+$a = new A('/');
+
+// Works
+echo $a, $a->__toString(), $a->__toString() . '', "\n";
+
+// Does not work - outputs parent::__toString()
+echo $a . '', "\n";
+
+--EXPECT--
+ -expected- -expected- -expected-
+ -expected-
diff --git a/ext/spl/tests/bug64106.phpt b/ext/spl/tests/bug64106.phpt
new file mode 100644
index 0000000..855caef
--- /dev/null
+++ b/ext/spl/tests/bug64106.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #64106: Segfault on SplFixedArray[][x] = y when extended
+--FILE--
+<?php
+
+class MyFixedArray extends SplFixedArray {
+ public function offsetGet($offset) {}
+}
+
+$array = new MyFixedArray(10);
+$array[][1] = 10;
+
+?>
+--EXPECTF--
+Notice: Indirect modification of overloaded element of MyFixedArray has no effect in %s on line %d
diff --git a/ext/spl/tests/bug64228.phpt b/ext/spl/tests/bug64228.phpt
new file mode 100644
index 0000000..3f30dd2
--- /dev/null
+++ b/ext/spl/tests/bug64228.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #64228 (RecursiveDirectoryIterator always assumes SKIP_DOTS)
+--FILE--
+<?php
+$dirs = array();
+$empty_dir = __DIR__ . "/empty";
+@mkdir($empty_dir);
+
+$i = new RecursiveDirectoryIterator($empty_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO); // Note the absence of FilesystemIterator::SKIP_DOTS
+foreach ($i as $key => $value) {
+ $dirs[] = $value->getFileName();
+}
+
+@rmdir($empty_dir);
+
+sort($dirs);
+print_r($dirs);
+?>
+--EXPECT--
+Array
+(
+ [0] => .
+ [1] => ..
+)
+
diff --git a/ext/spl/tests/bug64264.phpt b/ext/spl/tests/bug64264.phpt
new file mode 100644
index 0000000..e7b695b
--- /dev/null
+++ b/ext/spl/tests/bug64264.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #64264 (SPLFixedArray toArray problem)
+--FILE--
+<?php
+class MyFixedArray extends \SplFixedArray {
+ protected $foo;
+ protected $bar;
+}
+
+$myFixedArr = new MyFixedArray(1);
+$myFixedArr[0] = 'foo';
+$myFixedArr->setSize(2);
+$myFixedArr[1] = 'bar';
+$myFixedArr->setSize(5);
+$array = $myFixedArr->toArray();
+$array[2] = "ERROR";
+$array[3] = "ERROR";
+$array[4] = "ERROR";
+unset($array[4]);
+$myFixedArr->setSize(2);
+
+print_r($myFixedArr->toArray());
+?>
+--EXPECTF--
+Array
+(
+ [0] => foo
+ [1] => bar
+)
diff --git a/ext/spl/tests/class_implements_basic.phpt b/ext/spl/tests/class_implements_basic.phpt
new file mode 100644
index 0000000..1170b21
--- /dev/null
+++ b/ext/spl/tests/class_implements_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: Test class_implements() function : basic
+--FILE--
+<?php
+/* Prototype : array class_implements(mixed what [, bool autoload ])
+ * Description: Return all classes and interfaces implemented by SPL
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_implements() : basic ***\n";
+
+
+interface foo { }
+class bar implements foo {}
+
+var_dump(class_implements(new bar));
+var_dump(class_implements('bar'));
+
+
+?>
+===DONE===
+--EXPECT--
+*** Testing class_implements() : basic ***
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+===DONE===
diff --git a/ext/spl/tests/class_implements_basic2.phpt b/ext/spl/tests/class_implements_basic2.phpt
new file mode 100644
index 0000000..ea25e5b
--- /dev/null
+++ b/ext/spl/tests/class_implements_basic2.phpt
@@ -0,0 +1,74 @@
+--TEST--
+SPL: Test class_implements() function : basic
+--FILE--
+<?php
+/* Prototype : array class_implements(mixed what [, bool autoload ])
+ * Description: Return all classes and interfaces implemented by SPL
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_implements() : basic ***\n";
+
+
+interface foo { }
+class fooImpl implements foo {}
+
+interface bar { }
+class barImpl implements bar {}
+
+class foobarImpl implements foo, bar {}
+
+class fooViaBarImpl extends barImpl implements foo {}
+
+class fooExtended extends fooImpl {}
+
+s_var_dump(class_implements(new foobarImpl));
+s_var_dump(class_implements('foobarImpl'));
+s_var_dump(class_implements(new fooViaBarImpl));
+s_var_dump(class_implements('fooViaBarImpl'));
+s_var_dump(class_implements(new fooExtended));
+s_var_dump(class_implements('fooExtended'));
+
+
+function s_var_dump($arr) {
+ krsort($arr);
+ var_dump($arr);
+}
+?>
+===DONE===
+--EXPECT--
+*** Testing class_implements() : basic ***
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+===DONE===
diff --git a/ext/spl/tests/class_implements_variation.phpt b/ext/spl/tests/class_implements_variation.phpt
new file mode 100644
index 0000000..52fdbca
--- /dev/null
+++ b/ext/spl/tests/class_implements_variation.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: Test class_implements() function : variation - no interfaces and autoload
+--FILE--
+<?php
+/* Prototype : array class_implements(mixed what [, bool autoload ])
+ * Description: Return all classes and interfaces implemented by SPL
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_implements() : variation ***\n";
+
+echo "--- testing no interfaces ---\n";
+class fs {}
+var_dump(class_implements(new fs));
+var_dump(class_implements('fs'));
+
+echo "\n--- testing autoload ---\n";
+var_dump(class_implements('non-existent'));
+var_dump(class_implements('non-existent2', false));
+
+
+function __autoload($classname) {
+ echo "attempting to autoload $classname\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_implements() : variation ***
+--- testing no interfaces ---
+array(0) {
+}
+array(0) {
+}
+
+--- testing autoload ---
+attempting to autoload non-existent
+
+Warning: class_implements(): Class non-existent does not exist and could not be loaded in %s on line %d
+bool(false)
+
+Warning: class_implements(): Class non-existent2 does not exist in %s on line %d
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/class_implements_variation1.phpt b/ext/spl/tests/class_implements_variation1.phpt
new file mode 100644
index 0000000..d8a45ce
--- /dev/null
+++ b/ext/spl/tests/class_implements_variation1.phpt
@@ -0,0 +1,221 @@
+--TEST--
+SPL: Test class_implements() function : variation
+--FILE--
+<?php
+/* Prototype : array class_implements(mixed what [, bool autoload ])
+ * Description: Return all classes and interfaces implemented by SPL
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_implements() : variation ***\n";
+
+
+// Define error handler
+function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) {
+ if (error_reporting() != 0) {
+ // report non-silenced errors
+ echo "Error: $err_no - $err_msg, $filename($linenum)\n";
+ }
+}
+set_error_handler('test_error_handler');
+
+// Initialise function arguments not being substituted (if any)
+$autoload = true;
+
+//resource
+$res = fopen(__FILE__,'r');
+
+//get an unset variable
+$unset_var = 10;
+unset ($unset_var);
+
+// define some classes
+class classWithToString
+{
+ public function __toString() {
+ return "Class A object";
+ }
+}
+
+class classWithoutToString
+{
+}
+
+// heredoc string
+$heredoc = <<<EOT
+hello world
+EOT;
+
+// add arrays
+$index_array = array (1, 2, 3);
+$assoc_array = array ('one' => 1, 'two' => 2);
+
+//array of values to iterate over
+$inputs = array(
+
+ // int data
+ 'int 0' => 0,
+ 'int 1' => 1,
+ 'int 12345' => 12345,
+ 'int -12345' => -2345,
+
+ // float data
+ 'float 10.5' => 10.5,
+ 'float -10.5' => -10.5,
+ 'float 12.3456789000e10' => 12.3456789000e10,
+ 'float -12.3456789000e10' => -12.3456789000e10,
+ 'float .5' => .5,
+
+ // array data
+ 'empty array' => array(),
+ 'int indexed array' => $index_array,
+ 'associative array' => $assoc_array,
+ 'nested arrays' => array('foo', $index_array, $assoc_array),
+
+ // null data
+ 'uppercase NULL' => NULL,
+ 'lowercase null' => null,
+
+ // boolean data
+ 'lowercase true' => true,
+ 'lowercase false' =>false,
+ 'uppercase TRUE' =>TRUE,
+ 'uppercase FALSE' =>FALSE,
+
+ // empty data
+ 'empty string DQ' => "",
+ 'empty string SQ' => '',
+
+ // object data
+ 'instance of classWithToString' => new classWithToString(),
+ 'instance of classWithoutToString' => new classWithoutToString(),
+
+ // undefined data
+ 'undefined var' => @$undefined_var,
+
+ // unset data
+ 'unset var' => @$unset_var,
+
+ //resource
+ 'resource' => $res,
+);
+
+// loop through each element of the array for pattern
+
+foreach($inputs as $key =>$value) {
+ echo "\n--$key--\n";
+ var_dump( class_implements($value, $autoload) );
+};
+
+fclose($res);
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_implements() : variation ***
+
+--int 0--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--int 1--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--int 12345--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--int -12345--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--float 10.5--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--float -10.5--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--float 12.3456789000e10--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--float -12.3456789000e10--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--float .5--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--empty array--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--int indexed array--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--associative array--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--nested arrays--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase NULL--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase null--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase true--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase false--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase TRUE--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase FALSE--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--empty string DQ--
+Error: 2 - class_implements(): Class does not exist and could not be loaded, %s(%d)
+bool(false)
+
+--empty string SQ--
+Error: 2 - class_implements(): Class does not exist and could not be loaded, %s(%d)
+bool(false)
+
+--instance of classWithToString--
+array(0) {
+}
+
+--instance of classWithoutToString--
+array(0) {
+}
+
+--undefined var--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--unset var--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+
+--resource--
+Error: 2 - class_implements(): object or string expected, %s(%d)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/class_implements_variation2.phpt b/ext/spl/tests/class_implements_variation2.phpt
new file mode 100644
index 0000000..f695357
--- /dev/null
+++ b/ext/spl/tests/class_implements_variation2.phpt
@@ -0,0 +1,259 @@
+--TEST--
+SPL: Test class_implements() function : variation
+--FILE--
+<?php
+/* Prototype : array class_implements(mixed what [, bool autoload ])
+ * Description: Return all classes and interfaces implemented by SPL
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_implements() : variation ***\n";
+
+
+// Define error handler
+function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) {
+ if (error_reporting() != 0) {
+ // report non-silenced errors
+ echo "Error: $err_no - $err_msg, $filename($linenum)\n";
+ }
+}
+set_error_handler('test_error_handler');
+
+// Initialise function arguments not being substituted (if any)
+$class = 'Iterator';
+
+//resource
+$res = fopen(__FILE__,'r');
+
+//get an unset variable
+$unset_var = 10;
+unset ($unset_var);
+
+// define some classes
+class classWithToString
+{
+ public function __toString() {
+ return "Class A object";
+ }
+}
+
+class classWithoutToString
+{
+}
+
+// heredoc string
+$heredoc = <<<EOT
+hello world
+EOT;
+
+// add arrays
+$index_array = array (1, 2, 3);
+$assoc_array = array ('one' => 1, 'two' => 2);
+
+//array of values to iterate over
+$inputs = array(
+
+ // int data
+ 'int 0' => 0,
+ 'int 1' => 1,
+ 'int 12345' => 12345,
+ 'int -12345' => -2345,
+
+ // float data
+ 'float 10.5' => 10.5,
+ 'float -10.5' => -10.5,
+ 'float 12.3456789000e10' => 12.3456789000e10,
+ 'float -12.3456789000e10' => -12.3456789000e10,
+ 'float .5' => .5,
+
+ // array data
+ 'empty array' => array(),
+ 'int indexed array' => $index_array,
+ 'associative array' => $assoc_array,
+ 'nested arrays' => array('foo', $index_array, $assoc_array),
+
+ // null data
+ 'uppercase NULL' => NULL,
+ 'lowercase null' => null,
+
+ // boolean data
+ 'lowercase true' => true,
+ 'lowercase false' =>false,
+ 'uppercase TRUE' =>TRUE,
+ 'uppercase FALSE' =>FALSE,
+
+ // empty data
+ 'empty string DQ' => "",
+ 'empty string SQ' => '',
+
+ // object data
+ 'instance of classWithToString' => new classWithToString(),
+ 'instance of classWithoutToString' => new classWithoutToString(),
+
+ // undefined data
+ 'undefined var' => @$undefined_var,
+
+ // unset data
+ 'unset var' => @$unset_var,
+
+ //resource
+ 'resource' => $res,
+);
+
+// loop through each element of the array for pattern
+
+foreach($inputs as $key =>$value) {
+ echo "\n--$key--\n";
+ var_dump( class_implements($class, $value) );
+};
+
+fclose($res);
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_implements() : variation ***
+
+--int 0--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--int 1--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--int 12345--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--int -12345--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--float 10.5--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--float -10.5--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--float 12.3456789000e10--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--float -12.3456789000e10--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--float .5--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--empty array--
+Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--int indexed array--
+Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--associative array--
+Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--nested arrays--
+Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--uppercase NULL--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--lowercase null--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--lowercase true--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--lowercase false--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--uppercase TRUE--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--uppercase FALSE--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--empty string DQ--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--empty string SQ--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--instance of classWithToString--
+Error: 2 - class_implements() expects parameter 2 to be boolean, object given, %s(%d)
+bool(false)
+
+--instance of classWithoutToString--
+Error: 2 - class_implements() expects parameter 2 to be boolean, object given, %s(%d)
+bool(false)
+
+--undefined var--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--unset var--
+array(1) {
+ ["Traversable"]=>
+ string(11) "Traversable"
+}
+
+--resource--
+Error: 2 - class_implements() expects parameter 2 to be boolean, resource given, %s(%d)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/class_uses_basic.phpt b/ext/spl/tests/class_uses_basic.phpt
new file mode 100644
index 0000000..8aeb7b5
--- /dev/null
+++ b/ext/spl/tests/class_uses_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: Test class_implements() function : basic
+--FILE--
+<?php
+/* Prototype : array class_uses(mixed what [, bool autoload ])
+ * Description: Return all traits used by a class
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_uses() : basic ***\n";
+
+
+trait foo { }
+class bar { use foo; }
+
+var_dump(class_uses(new bar));
+var_dump(class_uses('bar'));
+
+
+?>
+===DONE===
+--EXPECT--
+*** Testing class_uses() : basic ***
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+===DONE===
diff --git a/ext/spl/tests/class_uses_basic2.phpt b/ext/spl/tests/class_uses_basic2.phpt
new file mode 100644
index 0000000..a0ffe8b
--- /dev/null
+++ b/ext/spl/tests/class_uses_basic2.phpt
@@ -0,0 +1,69 @@
+--TEST--
+SPL: Test class_uses() function : basic
+--FILE--
+<?php
+/* Prototype : array class_uses(mixed what [, bool autoload ])
+ * Description: Return all traits used by a class
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_uses() : basic ***\n";
+
+
+trait foo { }
+class fooUser { use foo; }
+
+trait bar { }
+class barUser { use bar; }
+
+class foobarUser { use foo, bar; }
+
+/** There is no semantics for traits in the inheritance chain.
+ Traits are flattend into a class, and that semantics is nothing
+ like a type, or interface, and thus, not propergated. */
+class fooViaBarUser extends barUser { use foo; }
+
+class fooExtended extends fooUser {}
+
+s_var_dump(class_uses(new foobarUser));
+s_var_dump(class_uses('foobarUser'));
+s_var_dump(class_uses(new fooViaBarUser));
+s_var_dump(class_uses('fooViaBarUser'));
+s_var_dump(class_uses(new fooExtended));
+s_var_dump(class_uses('fooExtended'));
+
+
+function s_var_dump($arr) {
+ krsort($arr);
+ var_dump($arr);
+}
+?>
+===DONE===
+--EXPECT--
+*** Testing class_uses() : basic ***
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+array(0) {
+}
+array(0) {
+}
+===DONE===
diff --git a/ext/spl/tests/class_uses_variation.phpt b/ext/spl/tests/class_uses_variation.phpt
new file mode 100644
index 0000000..9c21521
--- /dev/null
+++ b/ext/spl/tests/class_uses_variation.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: Test class_uses() function : variation - no interfaces and autoload
+--FILE--
+<?php
+/* Prototype : array class_uses(mixed what [, bool autoload ])
+ * Description: Return all traits used by a class
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_uses() : variation ***\n";
+
+echo "--- testing no traits ---\n";
+class fs {}
+var_dump(class_uses(new fs));
+var_dump(class_uses('fs'));
+
+echo "\n--- testing autoload ---\n";
+var_dump(class_uses('non-existent'));
+var_dump(class_uses('non-existent2', false));
+
+
+function __autoload($classname) {
+ echo "attempting to autoload $classname\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_uses() : variation ***
+--- testing no traits ---
+array(0) {
+}
+array(0) {
+}
+
+--- testing autoload ---
+attempting to autoload non-existent
+
+Warning: class_uses(): Class non-existent does not exist and could not be loaded in %s on line %d
+bool(false)
+
+Warning: class_uses(): Class non-existent2 does not exist in %s on line %d
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/class_uses_variation1.phpt b/ext/spl/tests/class_uses_variation1.phpt
new file mode 100644
index 0000000..aa0ba35
--- /dev/null
+++ b/ext/spl/tests/class_uses_variation1.phpt
@@ -0,0 +1,221 @@
+--TEST--
+SPL: Test class_uses() function : variation
+--FILE--
+<?php
+/* Prototype : array class_uses(mixed what [, bool autoload ])
+ * Description: Return all traits used by a class
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_uses() : variation ***\n";
+
+
+// Define error handler
+function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) {
+ if (error_reporting() != 0) {
+ // report non-silenced errors
+ echo "Error: $err_no - $err_msg, $filename($linenum)\n";
+ }
+}
+set_error_handler('test_error_handler');
+
+// Initialise function arguments not being substituted (if any)
+$autoload = true;
+
+//resource
+$res = fopen(__FILE__,'r');
+
+//get an unset variable
+$unset_var = 10;
+unset ($unset_var);
+
+// define some classes
+class classWithToString
+{
+ public function __toString() {
+ return "Class A object";
+ }
+}
+
+class classWithoutToString
+{
+}
+
+// heredoc string
+$heredoc = <<<EOT
+hello world
+EOT;
+
+// add arrays
+$index_array = array (1, 2, 3);
+$assoc_array = array ('one' => 1, 'two' => 2);
+
+//array of values to iterate over
+$inputs = array(
+
+ // int data
+ 'int 0' => 0,
+ 'int 1' => 1,
+ 'int 12345' => 12345,
+ 'int -12345' => -2345,
+
+ // float data
+ 'float 10.5' => 10.5,
+ 'float -10.5' => -10.5,
+ 'float 12.3456789000e10' => 12.3456789000e10,
+ 'float -12.3456789000e10' => -12.3456789000e10,
+ 'float .5' => .5,
+
+ // array data
+ 'empty array' => array(),
+ 'int indexed array' => $index_array,
+ 'associative array' => $assoc_array,
+ 'nested arrays' => array('foo', $index_array, $assoc_array),
+
+ // null data
+ 'uppercase NULL' => NULL,
+ 'lowercase null' => null,
+
+ // boolean data
+ 'lowercase true' => true,
+ 'lowercase false' =>false,
+ 'uppercase TRUE' =>TRUE,
+ 'uppercase FALSE' =>FALSE,
+
+ // empty data
+ 'empty string DQ' => "",
+ 'empty string SQ' => '',
+
+ // object data
+ 'instance of classWithToString' => new classWithToString(),
+ 'instance of classWithoutToString' => new classWithoutToString(),
+
+ // undefined data
+ 'undefined var' => @$undefined_var,
+
+ // unset data
+ 'unset var' => @$unset_var,
+
+ //resource
+ 'resource' => $res,
+);
+
+// loop through each element of the array for pattern
+
+foreach($inputs as $key =>$value) {
+ echo "\n--$key--\n";
+ var_dump( class_uses($value, $autoload) );
+};
+
+fclose($res);
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_uses() : variation ***
+
+--int 0--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--int 1--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--int 12345--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--int -12345--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--float 10.5--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--float -10.5--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--float 12.3456789000e10--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--float -12.3456789000e10--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--float .5--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--empty array--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--int indexed array--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--associative array--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--nested arrays--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase NULL--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase null--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase true--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--lowercase false--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase TRUE--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--uppercase FALSE--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--empty string DQ--
+Error: 2 - class_uses(): Class does not exist and could not be loaded, %s(%d)
+bool(false)
+
+--empty string SQ--
+Error: 2 - class_uses(): Class does not exist and could not be loaded, %s(%d)
+bool(false)
+
+--instance of classWithToString--
+array(0) {
+}
+
+--instance of classWithoutToString--
+array(0) {
+}
+
+--undefined var--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--unset var--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+
+--resource--
+Error: 2 - class_uses(): object or string expected, %s(%d)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/class_uses_variation2.phpt b/ext/spl/tests/class_uses_variation2.phpt
new file mode 100644
index 0000000..36c9623
--- /dev/null
+++ b/ext/spl/tests/class_uses_variation2.phpt
@@ -0,0 +1,261 @@
+--TEST--
+SPL: Test class_uses() function : variation
+--FILE--
+<?php
+/* Prototype : array class_uses(mixed what [, bool autoload ])
+ * Description: Return all traits used by a class
+ * Source code: ext/spl/php_spl.c
+ * Alias to functions:
+ */
+
+echo "*** Testing class_uses() : variation ***\n";
+
+trait foo {}
+class fooUser { use foo; }
+
+// Define error handler
+function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) {
+ if (error_reporting() != 0) {
+ // report non-silenced errors
+ echo "Error: $err_no - $err_msg, $filename($linenum)\n";
+ }
+}
+set_error_handler('test_error_handler');
+
+// Initialise function arguments not being substituted (if any)
+$class = 'fooUser';
+
+//resource
+$res = fopen(__FILE__,'r');
+
+//get an unset variable
+$unset_var = 10;
+unset ($unset_var);
+
+// define some classes
+class classWithToString
+{
+ public function __toString() {
+ return "Class A object";
+ }
+}
+
+class classWithoutToString
+{
+}
+
+// heredoc string
+$heredoc = <<<EOT
+hello world
+EOT;
+
+// add arrays
+$index_array = array (1, 2, 3);
+$assoc_array = array ('one' => 1, 'two' => 2);
+
+//array of values to iterate over
+$inputs = array(
+
+ // int data
+ 'int 0' => 0,
+ 'int 1' => 1,
+ 'int 12345' => 12345,
+ 'int -12345' => -2345,
+
+ // float data
+ 'float 10.5' => 10.5,
+ 'float -10.5' => -10.5,
+ 'float 12.3456789000e10' => 12.3456789000e10,
+ 'float -12.3456789000e10' => -12.3456789000e10,
+ 'float .5' => .5,
+
+ // array data
+ 'empty array' => array(),
+ 'int indexed array' => $index_array,
+ 'associative array' => $assoc_array,
+ 'nested arrays' => array('foo', $index_array, $assoc_array),
+
+ // null data
+ 'uppercase NULL' => NULL,
+ 'lowercase null' => null,
+
+ // boolean data
+ 'lowercase true' => true,
+ 'lowercase false' =>false,
+ 'uppercase TRUE' =>TRUE,
+ 'uppercase FALSE' =>FALSE,
+
+ // empty data
+ 'empty string DQ' => "",
+ 'empty string SQ' => '',
+
+ // object data
+ 'instance of classWithToString' => new classWithToString(),
+ 'instance of classWithoutToString' => new classWithoutToString(),
+
+ // undefined data
+ 'undefined var' => @$undefined_var,
+
+ // unset data
+ 'unset var' => @$unset_var,
+
+ //resource
+ 'resource' => $res,
+);
+
+// loop through each element of the array for pattern
+
+foreach($inputs as $key =>$value) {
+ echo "\n--$key--\n";
+ var_dump( class_uses($class, $value) );
+};
+
+fclose($res);
+
+?>
+===DONE===
+--EXPECTF--
+*** Testing class_uses() : variation ***
+
+--int 0--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--int 1--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--int 12345--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--int -12345--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--float 10.5--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--float -10.5--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--float 12.3456789000e10--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--float -12.3456789000e10--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--float .5--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--empty array--
+Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--int indexed array--
+Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--associative array--
+Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--nested arrays--
+Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d)
+bool(false)
+
+--uppercase NULL--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--lowercase null--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--lowercase true--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--lowercase false--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--uppercase TRUE--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--uppercase FALSE--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--empty string DQ--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--empty string SQ--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--instance of classWithToString--
+Error: 2 - class_uses() expects parameter 2 to be boolean, object given, %s(%d)
+bool(false)
+
+--instance of classWithoutToString--
+Error: 2 - class_uses() expects parameter 2 to be boolean, object given, %s(%d)
+bool(false)
+
+--undefined var--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--unset var--
+array(1) {
+ ["foo"]=>
+ string(3) "foo"
+}
+
+--resource--
+Error: 2 - class_uses() expects parameter 2 to be boolean, resource given, %s(%d)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/countable_class_basic1.phpt b/ext/spl/tests/countable_class_basic1.phpt
new file mode 100644
index 0000000..c64aad6
--- /dev/null
+++ b/ext/spl/tests/countable_class_basic1.phpt
@@ -0,0 +1,37 @@
+--TEST--
+SPL: Test shape of interface Countable.
+--SKIPIF--
+<?php
+// Skip the test case if Standard PHP Library(spl) is not installed
+ if( !extension_loaded('spl'))
+ {
+ die('skip spl is not installed');
+ }
+?>
+--FILE--
+<?php
+ReflectionClass::export('Countable');
+?>
+--EXPECTF--
+Interface [ <internal%s> interface Countable ] {
+
+ - Constants [0] {
+ }
+
+ - Static properties [0] {
+ }
+
+ - Static methods [0] {
+ }
+
+ - Properties [0] {
+ }
+
+ - Methods [1] {
+ Method [ <internal%s> abstract public method count ] {
+
+ - Parameters [0] {
+ }
+ }
+ }
+}
diff --git a/ext/spl/tests/countable_count_variation1.phpt b/ext/spl/tests/countable_count_variation1.phpt
new file mode 100644
index 0000000..642887d
--- /dev/null
+++ b/ext/spl/tests/countable_count_variation1.phpt
@@ -0,0 +1,68 @@
+--TEST--
+SPL: Countable::count() with wrong return types and exception.
+--FILE--
+<?php
+
+Class returnNull implements Countable {
+ function count() {
+ }
+}
+
+Class returnString implements Countable {
+ function count() {
+ return "hello";
+ }
+}
+
+Class returnObject implements Countable {
+ function count() {
+ return new returnObject;
+ }
+}
+
+Class returnArray implements Countable {
+ function count() {
+ return array(1,2,3);
+ }
+}
+
+Class throwException implements Countable {
+ function count() {
+ throw new Exception('Thrown from count');
+ }
+}
+
+
+echo "Count returns null:\n";
+var_dump(count(new returnNull));
+
+echo "Count returns a string:\n";
+var_dump(count(new returnString));
+
+echo "Count returns an object:\n";
+var_dump(count(new returnObject));
+
+echo "Count returns an array:\n";
+var_dump(count(new returnArray));
+
+echo "Count throws an exception:\n";
+try {
+ echo count(new throwException);
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECTF--
+Count returns null:
+int(0)
+Count returns a string:
+int(0)
+Count returns an object:
+
+Notice: Object of class returnObject could not be converted to int in %s on line 40
+int(1)
+Count returns an array:
+int(1)
+Count throws an exception:
+Thrown from count \ No newline at end of file
diff --git a/ext/spl/tests/dit_001.phpt b/ext/spl/tests/dit_001.phpt
new file mode 100644
index 0000000..a56166d
--- /dev/null
+++ b/ext/spl/tests/dit_001.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: Problem with casting to string
+--SKIPIF--
+<?php
+if (!defined('GLOB_ERR')) print "skip";
+--FILE--
+<?php
+$d = new DirectoryIterator('.');
+var_dump($d);
+var_dump(is_string($d));
+preg_match('/x/', $d);
+var_dump(is_string($d));
+?>
+===DONE===
+--EXPECTF--
+object(DirectoryIterator)#%d (4) {
+ %s"pathName"%s"SplFileInfo":private]=>
+ %s(%d) ".%c%s"
+ %s"fileName"%s"SplFileInfo":private]=>
+ %s(%d) "%s"
+ %s"glob"%s"DirectoryIterator":private]=>
+ bool(false)
+ %s"subPathName"%s"RecursiveDirectoryIterator":private]=>
+ %s(0) ""
+}
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/dit_001_noglob.phpt b/ext/spl/tests/dit_001_noglob.phpt
new file mode 100644
index 0000000..acb2092
--- /dev/null
+++ b/ext/spl/tests/dit_001_noglob.phpt
@@ -0,0 +1,27 @@
+--TEST--
+SPL: Problem with casting to string (no glob version)
+--SKIPIF--
+<?php
+if (defined('GLOB_ERR')) print "skip";
+--FILE--
+<?php
+$d = new DirectoryIterator('.');
+var_dump($d);
+var_dump(is_string($d));
+preg_match('/x/', $d);
+var_dump(is_string($d));
+?>
+===DONE===
+--EXPECTF--
+object(DirectoryIterator)#%d (3) {
+ %s"pathName"%s"SplFileInfo":private]=>
+ %s(%d) ".%c%s"
+ %s"fileName"%s"SplFileInfo":private]=>
+ %s(%d) "%s"
+ %s"subPathName"%s"RecursiveDirectoryIterator":private]=>
+ %s(0) ""
+}
+bool(false)
+bool(false)
+===DONE===
+
diff --git a/ext/spl/tests/dit_002.phpt b/ext/spl/tests/dit_002.phpt
new file mode 100644
index 0000000..a266542
--- /dev/null
+++ b/ext/spl/tests/dit_002.phpt
@@ -0,0 +1,77 @@
+--TEST--
+SPL: DirectoryIterator defaults
+--SKIPIF--
+<?php if (!extension_loaded("spl") || !extension_loaded('reflection') || !defined('GLOB_ERR')) print "skip"; ?>
+--FILE--
+<?php
+
+$classes = array(
+ 'DirectoryIterator' => 0,
+ 'FilesystemIterator' => 1,
+ 'RecursiveDirectoryIterator' => 1,
+ 'GlobIterator' => 1,
+);
+
+foreach ($classes as $class => $flags) {
+ echo "===$class===\n";
+ $ref = new ReflectionClass($class);
+ $obj = $ref->newInstance('glob://*');
+ echo get_class($obj->current()) . "\n";
+ if ($flags)
+ {
+ var_dump($obj->getFlags());
+ $flags = array(
+ FilesystemIterator::CURRENT_AS_FILEINFO => 0,
+ FilesystemIterator::CURRENT_AS_SELF => 0,
+ FilesystemIterator::CURRENT_AS_PATHNAME => 1,
+ );
+ foreach($flags as $flag => $isstring) {
+ $obj->setFlags($flag);
+ $obj->rewind();
+ var_dump($obj->getFlags());
+ if ($isstring) {
+ $val = $obj->current();
+ if (is_string($val)) {
+ var_dump(true);
+ } else {
+ var_dump($val);
+ }
+ } else {
+ echo get_class($obj->current()) . "\n";
+ }
+ }
+ }
+}
+?>
+===DONE===
+--EXPECTF--
+===DirectoryIterator===
+DirectoryIterator
+===FilesystemIterator===
+SplFileInfo
+int(%d)
+int(0)
+SplFileInfo
+int(16)
+FilesystemIterator
+int(32)
+bool(true)
+===RecursiveDirectoryIterator===
+SplFileInfo
+int(0)
+int(0)
+SplFileInfo
+int(16)
+RecursiveDirectoryIterator
+int(32)
+bool(true)
+===GlobIterator===
+SplFileInfo
+int(0)
+int(0)
+SplFileInfo
+int(16)
+GlobIterator
+int(32)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/dit_003.phpt b/ext/spl/tests/dit_003.phpt
new file mode 100644
index 0000000..4ffc292
--- /dev/null
+++ b/ext/spl/tests/dit_003.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: FilesystemIterator and foreach
+--FILE--
+<?php
+$count = 0;
+foreach(new FilesystemIterator(__DIR__) as $ent)
+{
+ ++$count;
+}
+var_dump($count > 0);
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/dit_004.phpt b/ext/spl/tests/dit_004.phpt
new file mode 100644
index 0000000..4ad0e4b
--- /dev/null
+++ b/ext/spl/tests/dit_004.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: DirectoryIterator and clone
+--FILE--
+<?php
+$a = new DirectoryIterator(__DIR__);
+$b = clone $a;
+var_dump((string)$b == (string)$a);
+var_dump($a->key(), $b->key());
+$a->next();
+$a->next();
+$a->next();
+$c = clone $a;
+var_dump((string)$c == (string)$a);
+var_dump($a->key(), $c->key());
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+int(0)
+int(0)
+bool(true)
+int(3)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/dit_005.phpt b/ext/spl/tests/dit_005.phpt
new file mode 100644
index 0000000..52a3351
--- /dev/null
+++ b/ext/spl/tests/dit_005.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: FilesystemIterator and clone
+--FILE--
+<?php
+$a = new FileSystemIterator(__DIR__);
+$b = clone $a;
+var_dump((string)$b == (string)$a);
+var_dump($a->key() == $b->key());
+$a->next();
+$a->next();
+$a->next();
+$c = clone $a;
+var_dump((string)$c == (string)$a);
+var_dump($a->key() == $c->key());
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/dit_006.phpt b/ext/spl/tests/dit_006.phpt
new file mode 100644
index 0000000..1e627a2
--- /dev/null
+++ b/ext/spl/tests/dit_006.phpt
@@ -0,0 +1,50 @@
+--TEST--
+SPL: DirectoryIterator and seek
+--FILE--
+<?php
+$di = new DirectoryIterator(__DIR__);
+$di->seek(2);
+
+$n = 0;
+while ($di->valid()) {
+ $n++;
+ $di->next();
+}
+
+echo "With seek(2) we get $n\n";
+$di->seek(0);
+
+$m = 0;
+while ($di->valid()) {
+ $m++;
+ $di->next();
+}
+echo "With seek(0) we get $m\n";
+
+$o = 0;
+$di->rewind();
+while ($di->valid()) {
+ $o++;
+ $di->next();
+}
+
+echo "Without seek we get $o\n";
+
+$p = 0;
+$di->seek($o+1);
+while ($di->valid()) {
+ $p++;
+ $di->next();
+}
+
+var_dump($n !== $m, $m === $o, $p === 0);
+?>
+===DONE===
+--EXPECTF--
+With seek(2) we get %d
+With seek(0) we get %d
+Without seek we get %d
+bool(true)
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/dllist_001.phpt b/ext/spl/tests/dllist_001.phpt
new file mode 100644
index 0000000..e27f23c
--- /dev/null
+++ b/ext/spl/tests/dllist_001.phpt
@@ -0,0 +1,63 @@
+--TEST--
+SPL: DoublyLinkedList: std operations
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+// errors
+try {
+ $dll->pop();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ $dll->shift();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+// data consistency
+$a = 2;
+$dll->push($a);
+echo $dll->pop()."\n";
+
+$a = 2;
+$dll->unshift($a);
+echo $dll->shift()."\n";
+
+// peakable
+$dll->push(1);
+$dll->push(2);
+echo $dll->top()."\n";
+echo $dll->bottom()."\n";
+$dll->pop();
+$dll->pop();
+
+// countable
+$dll->push(NULL);
+$dll->push(NULL);
+echo count($dll)."\n";
+echo $dll->count()."\n";
+var_dump($dll->pop());
+var_dump($dll->pop());
+
+// clonable
+$dll->push(2);
+$dll_clone = clone $dll;
+$dll_clone->pop();
+echo count($dll)."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't pop from an empty datastructure
+Exception: Can't shift from an empty datastructure
+2
+2
+2
+1
+2
+2
+NULL
+NULL
+1
+===DONE===
diff --git a/ext/spl/tests/dllist_002.phpt b/ext/spl/tests/dllist_002.phpt
new file mode 100644
index 0000000..e956de6
--- /dev/null
+++ b/ext/spl/tests/dllist_002.phpt
@@ -0,0 +1,60 @@
+--TEST--
+SPL: DoublyLinkedList: iterators
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->push(2);
+$dll->push(3);
+$dll->push(4);
+
+$dll2 = clone $dll;
+
+// std iterator
+foreach($dll as $k=>$v) {
+ echo "$k=>$v\n";
+ // inner iterator
+ foreach($dll as $k2=>$v2) {
+ echo "->$k2=>$v2\n";
+ }
+}
+
+echo "# deleted\n";
+
+foreach($dll as $k=>$v) {
+ echo "$k=>$v\n";
+ unset($dll);
+}
+
+echo "# while popping\n";
+
+foreach($dll2 as $k=>$v) {
+ echo "$k=>$v\n";
+ echo "popped ".$dll2->pop()."\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+0=>2
+->0=>2
+->1=>3
+->2=>4
+1=>3
+->0=>2
+->1=>3
+->2=>4
+2=>4
+->0=>2
+->1=>3
+->2=>4
+# deleted
+0=>2
+1=>3
+2=>4
+# while popping
+0=>2
+popped 4
+1=>3
+popped 3
+===DONE===
diff --git a/ext/spl/tests/dllist_003.phpt b/ext/spl/tests/dllist_003.phpt
new file mode 100644
index 0000000..9a95568
--- /dev/null
+++ b/ext/spl/tests/dllist_003.phpt
@@ -0,0 +1,43 @@
+--TEST--
+SPL: DoublyLinkedList: iterator modes
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->push(2);
+$dll->push(3);
+$dll->push(4);
+
+$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
+
+foreach ($dll as $k => $v) {
+ echo "$k=>$v\n";
+}
+
+$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO);
+foreach ($dll as $k => $v) {
+ echo "$k=>$v\n";
+}
+
+$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE);
+var_dump($dll->count());
+foreach ($dll as $k => $v) {
+ echo "$k=>$v\n";
+}
+var_dump($dll->count());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+2=>4
+1=>3
+0=>2
+0=>2
+1=>3
+2=>4
+int(3)
+0=>2
+0=>3
+0=>4
+int(0)
+===DONE===
diff --git a/ext/spl/tests/dllist_004.phpt b/ext/spl/tests/dllist_004.phpt
new file mode 100644
index 0000000..44d9611
--- /dev/null
+++ b/ext/spl/tests/dllist_004.phpt
@@ -0,0 +1,61 @@
+--TEST--
+SPL: DoublyLinkedList: Stacks
+--FILE--
+<?php
+$stack = new SplStack();
+// errors
+try {
+ $stack->pop();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ $stack->shift();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+// data consistency
+$a = 2;
+$stack->push($a);
+echo $stack->pop()."\n";
+
+// peakable
+$stack->push(1);
+$stack->push(2);
+echo $stack->top()."\n";
+
+// iterable
+foreach ($stack as $elem) {
+ echo "[$elem]\n";
+}
+
+// countable
+$stack->push(NULL);
+$stack->push(NULL);
+echo count($stack)."\n";
+echo $stack->count()."\n";
+var_dump($stack->pop());
+var_dump($stack->pop());
+
+// clonable
+$stack->push(2);
+$stack_clone = clone $stack;
+$stack_clone->pop();
+echo count($stack)."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't pop from an empty datastructure
+Exception: Can't shift from an empty datastructure
+2
+2
+[2]
+[1]
+4
+4
+NULL
+NULL
+3
+===DONE===
diff --git a/ext/spl/tests/dllist_005.phpt b/ext/spl/tests/dllist_005.phpt
new file mode 100644
index 0000000..33161ba
--- /dev/null
+++ b/ext/spl/tests/dllist_005.phpt
@@ -0,0 +1,61 @@
+--TEST--
+SPL: DoublyLinkedList: Queues
+--FILE--
+<?php
+$queue = new SplQueue();
+// errors
+try {
+ $queue->dequeue();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ $queue->shift();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+// data consistency
+$a = 2;
+$queue->enqueue($a);
+echo $queue->dequeue()."\n";
+
+// peakable
+$queue->enqueue(1);
+$queue->enqueue(2);
+echo $queue->top()."\n";
+
+// iterable
+foreach ($queue as $elem) {
+ echo "[$elem]\n";
+}
+
+// countable
+$queue->enqueue(NULL);
+$queue->enqueue(NULL);
+echo count($queue)."\n";
+echo $queue->count()."\n";
+var_dump($queue->dequeue());
+var_dump($queue->dequeue());
+
+// clonable
+$queue->enqueue(2);
+$queue_clone = clone $queue;
+$queue_clone->dequeue();
+echo count($queue)."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't shift from an empty datastructure
+Exception: Can't shift from an empty datastructure
+2
+2
+[1]
+[2]
+4
+4
+int(1)
+int(2)
+3
+===DONE===
diff --git a/ext/spl/tests/dllist_006.phpt b/ext/spl/tests/dllist_006.phpt
new file mode 100644
index 0000000..b4055dc
--- /dev/null
+++ b/ext/spl/tests/dllist_006.phpt
@@ -0,0 +1,62 @@
+--TEST--
+SPL: DoublyLinkedList: ArrayAccess
+--FILE--
+<?php
+$a = new SplDoublyLinkedList();
+$a->push(1);
+$a->push(2);
+$a->push(3);
+
+$a[] = "foo";
+$a[3] = 4;
+
+var_dump($a[0]);
+var_dump($a[1]);
+var_dump($a[2]);
+var_dump($a[3]);
+
+echo "Unsetting..\n";
+var_dump($a[2]);
+unset($a[2]);
+var_dump($a[2]);
+
+
+try {
+ var_dump($a["1"]);
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ var_dump($a["a"]);
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ var_dump($a["0"]);
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ var_dump($a["9"]);
+} catch (OutOfRangeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+int(2)
+int(3)
+int(4)
+Unsetting..
+int(3)
+int(4)
+int(2)
+Exception: Offset invalid or out of range
+int(1)
+Exception: Offset invalid or out of range
+===DONE===
diff --git a/ext/spl/tests/dllist_007.phpt b/ext/spl/tests/dllist_007.phpt
new file mode 100644
index 0000000..38f801f
--- /dev/null
+++ b/ext/spl/tests/dllist_007.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: DoublyLinkedList: Iterator
+--FILE--
+<?php
+$a = new SplDoublyLinkedList();
+$a->push(1);
+$a->push(2);
+$a->push(3);
+
+$a->rewind();
+while ($a->valid()) {
+ var_dump($a->current(), $a->next());
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+NULL
+int(2)
+NULL
+int(3)
+NULL
+===DONE===
diff --git a/ext/spl/tests/dllist_008.phpt b/ext/spl/tests/dllist_008.phpt
new file mode 100644
index 0000000..ab37d83
--- /dev/null
+++ b/ext/spl/tests/dllist_008.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: SplDoublyLinkedList with overriden count()
+--FILE--
+<?php
+$obj = new SplDoublyLinkedList();
+$obj[] = 1;
+$obj[] = 2;
+var_dump(count($obj));
+class SplDoublyLinkedList2 extends SplDoublyLinkedList{
+ public function count() {
+ return -parent::count();
+ }
+}
+$obj = new SplDoublyLinkedList2();
+$obj[] = 1;
+$obj[] = 2;
+var_dump(count($obj));
+?>
+--EXPECT--
+int(2)
+int(-2)
diff --git a/ext/spl/tests/dllist_010.phpt b/ext/spl/tests/dllist_010.phpt
new file mode 100644
index 0000000..7e38955
--- /dev/null
+++ b/ext/spl/tests/dllist_010.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: DoublyLinkedList: prev
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->push(1);
+$dll->push(2);
+$dll->push(3);
+$dll->push(4);
+
+
+$dll->rewind();
+$dll->prev();
+var_dump($dll->current());
+$dll->rewind();
+var_dump($dll->current());
+$dll->next();
+var_dump($dll->current());
+$dll->next();
+$dll->next();
+var_dump($dll->current());
+$dll->prev();
+var_dump($dll->current());
+
+?>
+===DONE===
+--EXPECT--
+NULL
+int(1)
+int(2)
+int(4)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/dllist_011.phpt b/ext/spl/tests/dllist_011.phpt
new file mode 100644
index 0000000..b9be872
--- /dev/null
+++ b/ext/spl/tests/dllist_011.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SPL: DoublyLinkedList: prev
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->rewind();
+$dll->prev();
+var_dump($dll->current());
+?>
+===DONE===
+--EXPECT--
+NULL
+===DONE===
diff --git a/ext/spl/tests/dllist_012.phpt b/ext/spl/tests/dllist_012.phpt
new file mode 100644
index 0000000..4eec9bd
--- /dev/null
+++ b/ext/spl/tests/dllist_012.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: DoublyLinkedList: recursive var_dump
+--FILE--
+<?php
+$a = new SplDoublyLinkedList;
+$a[] = $a;
+
+var_dump($a);
+?>
+===DONE===
+--EXPECTF--
+object(SplDoublyLinkedList)#%d (2) {
+ ["flags":"SplDoublyLinkedList":private]=>
+ int(0)
+ ["dllist":"SplDoublyLinkedList":private]=>
+ array(1) {
+ [0]=>
+ *RECURSION*
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/dllist_memleak.phpt b/ext/spl/tests/dllist_memleak.phpt
new file mode 100644
index 0000000..9bae68b
--- /dev/null
+++ b/ext/spl/tests/dllist_memleak.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: DoublyLinkedList: memory leak when iterator pointer isn't at the last element
+--FILE--
+<?php
+$dll = new SplDoublyLinkedList();
+$dll->push(1);
+$dll->push(2);
+$dll->push(3);
+$dll->push(4);
+
+
+$dll->rewind();
+echo $dll->current()."\n";
+$dll->next();
+$dll->next();
+echo $dll->current()."\n";
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+1
+3
+===DONE===
diff --git a/ext/spl/tests/fileobject_001.phpt b/ext/spl/tests/fileobject_001.phpt
new file mode 100644
index 0000000..61f688d
--- /dev/null
+++ b/ext/spl/tests/fileobject_001.phpt
@@ -0,0 +1,88 @@
+--TEST--
+SPL: SplFileObject::seek'ing
+--FILE--
+<?php
+
+$o = new SplFileObject(dirname(__FILE__) . '/fileobject_001a.txt');
+
+var_dump($o->key());
+var_dump($o->current());
+$o->setFlags(SplFileObject::DROP_NEW_LINE);
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->next();
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->rewind();
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->seek(4);
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+
+echo "===A===\n";
+foreach($o as $n => $l)
+{
+ var_dump($n, $l);
+}
+
+echo "===B===\n";
+$o = new SplFileObject(dirname(__FILE__) . '/fileobject_001b.txt');
+$o->setFlags(SplFileObject::DROP_NEW_LINE);
+foreach($o as $n => $l)
+{
+ var_dump($n, $l);
+}
+
+?>
+===DONE===
+--EXPECT--
+int(0)
+string(2) "0
+"
+int(0)
+string(2) "0
+"
+int(0)
+int(1)
+string(1) "1"
+int(1)
+int(0)
+string(1) "0"
+int(0)
+int(4)
+string(1) "4"
+int(4)
+===A===
+int(0)
+string(1) "0"
+int(1)
+string(1) "1"
+int(2)
+string(1) "2"
+int(3)
+string(1) "3"
+int(4)
+string(1) "4"
+int(5)
+string(1) "5"
+int(6)
+string(0) ""
+===B===
+int(0)
+string(1) "0"
+int(1)
+string(1) "1"
+int(2)
+string(1) "2"
+int(3)
+string(1) "3"
+int(4)
+string(1) "4"
+int(5)
+string(1) "5"
+===DONE===
diff --git a/ext/spl/tests/fileobject_001a.txt b/ext/spl/tests/fileobject_001a.txt
new file mode 100755
index 0000000..e8371f0
--- /dev/null
+++ b/ext/spl/tests/fileobject_001a.txt
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+5
diff --git a/ext/spl/tests/fileobject_001b.txt b/ext/spl/tests/fileobject_001b.txt
new file mode 100755
index 0000000..0c4a8b5
--- /dev/null
+++ b/ext/spl/tests/fileobject_001b.txt
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+5 \ No newline at end of file
diff --git a/ext/spl/tests/fileobject_002.phpt b/ext/spl/tests/fileobject_002.phpt
new file mode 100644
index 0000000..8031e98
--- /dev/null
+++ b/ext/spl/tests/fileobject_002.phpt
@@ -0,0 +1,122 @@
+--TEST--
+SPL: SplFileObject::fgetc
+--FILE--
+<?php
+
+function test($name)
+{
+ echo "===$name===\n";
+
+ $o = new SplFileObject(dirname(__FILE__) . '/' . $name);
+
+ var_dump($o->key());
+ while(($c = $o->fgetc()) !== false)
+ {
+ var_dump($o->key(), $c, $o->eof());
+ }
+ echo "===EOF?===\n";
+ var_dump($o->eof());
+ var_dump($o->key());
+ var_dump($o->eof());
+}
+
+test('fileobject_001a.txt');
+test('fileobject_001b.txt');
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===fileobject_001a.txt===
+int(0)
+int(0)
+string(1) "0"
+bool(false)
+int(1)
+string(1) "
+"
+bool(false)
+int(1)
+string(1) "1"
+bool(false)
+int(2)
+string(1) "
+"
+bool(false)
+int(2)
+string(1) "2"
+bool(false)
+int(3)
+string(1) "
+"
+bool(false)
+int(3)
+string(1) "3"
+bool(false)
+int(4)
+string(1) "
+"
+bool(false)
+int(4)
+string(1) "4"
+bool(false)
+int(5)
+string(1) "
+"
+bool(false)
+int(5)
+string(1) "5"
+bool(false)
+int(6)
+string(1) "
+"
+bool(false)
+===EOF?===
+bool(true)
+int(6)
+bool(true)
+===fileobject_001b.txt===
+int(0)
+int(0)
+string(1) "0"
+bool(false)
+int(1)
+string(1) "
+"
+bool(false)
+int(1)
+string(1) "1"
+bool(false)
+int(2)
+string(1) "
+"
+bool(false)
+int(2)
+string(1) "2"
+bool(false)
+int(3)
+string(1) "
+"
+bool(false)
+int(3)
+string(1) "3"
+bool(false)
+int(4)
+string(1) "
+"
+bool(false)
+int(4)
+string(1) "4"
+bool(false)
+int(5)
+string(1) "
+"
+bool(false)
+int(5)
+string(1) "5"
+bool(false)
+===EOF?===
+bool(true)
+int(5)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/fileobject_003.phpt b/ext/spl/tests/fileobject_003.phpt
new file mode 100644
index 0000000..6cc650b
--- /dev/null
+++ b/ext/spl/tests/fileobject_003.phpt
@@ -0,0 +1,114 @@
+--TEST--
+SPL: SplFileInfo cloning
+--FILE--
+<?php
+
+function test($name, $lc, $lp)
+{
+ static $i = 0;
+ echo "===$i===\n";
+ $i++;
+
+ $o = new SplFileInfo($name);
+
+ var_dump($o);
+ $c = clone $o;
+ var_dump($c);
+ var_dump($o === $c);
+ var_dump($o == $c);
+ var_dump($o->getPathname() == $c->getPathname());
+
+ try {
+ $f = new SplFileObject($name);
+ var_dump($name);
+ var_dump($f->getPathName());
+ $l = substr($f->getPathName(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lc);
+ var_dump($f->getFileName());
+ $l = substr($f->getFileName(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lc);
+ var_dump($f->getPath());
+ $l = substr($f->getPath(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lp);
+ } catch (LogicException $e) {
+ echo "LogicException: ".$e->getMessage()."\n";
+ }
+ try {
+ $fo = $o->openFile();
+ var_dump($fo->getPathName(), $fo->getFileName(), $fo->getPath());
+ } catch (LogicException $e) {
+ echo "LogicException: ".$e->getMessage()."\n";
+ }
+}
+
+test(dirname(__FILE__) . '/' . 'fileobject_001a.txt', 't', substr(dirname(__FILE__),-1));
+test(dirname(__FILE__) . '/', substr(dirname(__FILE__),-1), 'l');
+test(dirname(__FILE__), substr(dirname(__FILE__),-1), 'l');
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===0===
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "fileobject_001a.txt"
+}
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "fileobject_001a.txt"
+}
+bool(false)
+bool(true)
+bool(true)
+%s(%d) "%sfileobject_001a.txt"
+string(%d) "%sfileobject_001a.txt"
+bool(true)
+string(19) "fileobject_001a.txt"
+bool(true)
+string(%d) "%stests"
+bool(true)
+string(%d) "%sfileobject_001a.txt"
+string(19) "fileobject_001a.txt"
+string(%d) "%stests"
+===1===
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "%s"
+}
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "%s"
+}
+bool(false)
+bool(true)
+bool(true)
+LogicException: Cannot use SplFileObject with directories
+LogicException: Cannot use SplFileObject with directories
+===2===
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "%s"
+}
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%s"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "%s"
+}
+bool(false)
+bool(true)
+bool(true)
+LogicException: Cannot use SplFileObject with directories
+LogicException: Cannot use SplFileObject with directories
+===DONE===
diff --git a/ext/spl/tests/fileobject_004.phpt b/ext/spl/tests/fileobject_004.phpt
new file mode 100644
index 0000000..02e6725
--- /dev/null
+++ b/ext/spl/tests/fileobject_004.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject realpath and include_path
+--FILE--
+<?php
+
+set_include_path('tests');
+
+chdir(dirname(dirname(__FILE__))); // ext/spl
+
+
+$fo = new SplFileObject('fileobject_004.phpt', 'r', true);
+
+var_dump($fo->getPath());
+var_dump($fo->getFilename());
+var_dump($fo->getRealPath());
+?>
+==DONE==
+--EXPECTF--
+string(%d) "%sspl%stests"
+string(19) "fileobject_004.phpt"
+string(%d) "%sspl%stests%sfileobject_004.phpt"
+==DONE==
diff --git a/ext/spl/tests/fileobject_005.phpt b/ext/spl/tests/fileobject_005.phpt
new file mode 100644
index 0000000..fa9e6db
--- /dev/null
+++ b/ext/spl/tests/fileobject_005.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SPL: SplFileObject truncate tests
+--CREDITS--
+Mark Ammann
+#Hackday Webtuesday 2008-05-24
+--FILE--
+<?php
+
+set_include_path(dirname(dirname(__FILE__)));
+
+$path = dirname(__FILE__).DIRECTORY_SEPARATOR.'fileobject_005.txt';
+touch($path);
+
+$fo = new SplFileObject('tests'.DIRECTORY_SEPARATOR.'fileobject_005.txt', 'w+', true);
+$fo->fwrite("blahlubba");
+var_dump($fo->ftruncate(4));
+
+$fo->rewind();
+var_dump($fo->fgets(8));
+
+$fo->rewind();
+$fo->fwrite("blahlubba");
+
+// This should throw a warning and return NULL since an argument is missing
+var_dump($fo->ftruncate());
+
+?>
+==DONE==
+--CLEAN--
+<?php
+$path = dirname(__FILE__).DIRECTORY_SEPARATOR.'fileobject_005.txt';
+unlink($path);
+?>
+--EXPECTF--
+bool(true)
+
+Warning: SplFileObject::fgets() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
+
+Warning: SplFileObject::ftruncate() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+==DONE== \ No newline at end of file
diff --git a/ext/spl/tests/fileobject_checktype_basic.phpt b/ext/spl/tests/fileobject_checktype_basic.phpt
new file mode 100644
index 0000000..650204e
--- /dev/null
+++ b/ext/spl/tests/fileobject_checktype_basic.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: SplFileObject::isFile/isDir/isLink
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--FILE--
+<?php
+$s = new SplFileObject(__FILE__);
+var_dump($s->isFile());
+var_dump($s->isDir());
+var_dump($s->isLink());
+?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(false)
diff --git a/ext/spl/tests/fileobject_getbasename_basic.phpt b/ext/spl/tests/fileobject_getbasename_basic.phpt
new file mode 100644
index 0000000..34fecdc
--- /dev/null
+++ b/ext/spl/tests/fileobject_getbasename_basic.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SPL: SplFileObject::getBasename
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--FILE--
+<?php
+$file = __FILE__;
+$s = new SplFileObject( __FILE__ );
+echo $s->getBasename();
+?>
+--EXPECT--
+fileobject_getbasename_basic.php
diff --git a/ext/spl/tests/fileobject_getcurrentline_basic.phpt b/ext/spl/tests/fileobject_getcurrentline_basic.phpt
new file mode 100644
index 0000000..607fce6
--- /dev/null
+++ b/ext/spl/tests/fileobject_getcurrentline_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplFileObject::getCurrentLine
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--FILE--
+<?php
+//line 2
+//line 3
+//line 4
+//line 5
+$s = new SplFileObject(__FILE__);
+$s->seek(1);
+echo $s->getCurrentLine();
+echo $s->getCurrentLine();
+?>
+--EXPECT--
+//line 3
+//line 4
diff --git a/ext/spl/tests/fileobject_getfileinfo_basic.phpt b/ext/spl/tests/fileobject_getfileinfo_basic.phpt
new file mode 100644
index 0000000..97d0de2
--- /dev/null
+++ b/ext/spl/tests/fileobject_getfileinfo_basic.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: SplFileObject::getFileInfo
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--INI--
+include_path=.
+--FILE--
+<?php
+$file = __FILE__;
+$s = new SplFileObject( $file );
+var_dump($fi = $s->getFileInfo(), (string)$fi);
+
+$d = new SplFileInfo( __DIR__ );
+echo "\n";
+var_dump($fi = $d->getFileInfo(), (string)$fi);
+$d = new SplFileInfo( __DIR__."/" );
+echo "\n";
+var_dump($fi = $d->getFileInfo(), (string)$fi);
+?>
+--EXPECTF--
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%sext%espl%etests%efileobject_getfileinfo_basic.php"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "fileobject_getfileinfo_basic.php"
+}
+string(%d) "%sext%espl%etests%efileobject_getfileinfo_basic.php"
+
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%sext%espl%etests"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "tests"
+}
+string(%d) "%sext%espl%etests"
+
+object(SplFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "%sext%espl%etests"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "tests"
+}
+string(%d) "%sext%espl%etests"
diff --git a/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt b/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt
new file mode 100644
index 0000000..b08a711
--- /dev/null
+++ b/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: SplFileObject::getMaxLineLen()
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--INI--
+include_path=.
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->setMaxLineLen( 7 );
+echo $s->getMaxLineLen();
+?>
+--EXPECT--
+7
diff --git a/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt b/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt
new file mode 100644
index 0000000..3c0c9ee
--- /dev/null
+++ b/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: SplFileObject::getMaxLineLen error 001
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--INI--
+include_path=.
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->getMaxLineLen('string');
+
+?>
+--EXPECTF--
+Warning: SplFileObject::getMaxLineLen() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/spl/tests/fileobject_getsize_basic.phpt b/ext/spl/tests/fileobject_getsize_basic.phpt
new file mode 100644
index 0000000..da9f708
--- /dev/null
+++ b/ext/spl/tests/fileobject_getsize_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplFileObject::getSize
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--INI--
+include_path=.
+--FILE--
+<?php
+$file = __DIR__ ."/data.txt";
+file_put_contents($file, "foobar");
+
+$s = new SplFileObject( $file );
+echo $s->getSize();
+?>
+--CLEAN--
+<?php
+$file = __DIR__ ."/data.txt";
+unlink($file);
+?>
+--EXPECT--
+6
diff --git a/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt b/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt
new file mode 100644
index 0000000..c230766
--- /dev/null
+++ b/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: SplFileObject::setMaxLineLen
+--CREDITS--
+H�vard Eide <nucleuz at gmail.com>
+#Testfest php.no
+--INI--
+include_path=.
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->setMaxLineLen( 3);
+echo $s->getCurrentLine();
+?>
+--EXPECT--
+<?
diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt
new file mode 100644
index 0000000..6bfdfdc
--- /dev/null
+++ b/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: SplFileObject::setMaxLineLen error 001()
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+try {
+ $s->setMaxLineLen(-1);
+}
+catch (DomainException $e) {
+ echo 'DomainException thrown';
+}
+
+?>
+--EXPECT--
+DomainException thrown
diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt
new file mode 100644
index 0000000..dad59fc
--- /dev/null
+++ b/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::setMaxLineLen error 002
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->setMaxLineLen();
+
+?>
+--EXPECTF--
+Warning: SplFileObject::setMaxLineLen() expects exactly 1 parameter, 0 given in %s on line %d
diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt
new file mode 100644
index 0000000..8dc50d5
--- /dev/null
+++ b/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplFileObject::setMaxLineLen error 003
+--CREDITS--
+Erwin Poeze <erwin.poeze at gmail.com>
+--FILE--
+<?php
+$s = new SplFileObject( __FILE__ );
+$s->setMaxLineLen('string');
+
+?>
+--EXPECTF--
+Warning: SplFileObject::setMaxLineLen() expects parameter 1 to be long, string given in %s on line %d
diff --git a/ext/spl/tests/filesystemiterator_flags.phpt b/ext/spl/tests/filesystemiterator_flags.phpt
new file mode 100644
index 0000000..6353456
--- /dev/null
+++ b/ext/spl/tests/filesystemiterator_flags.phpt
@@ -0,0 +1,40 @@
+--TEST--
+SPL: FilesystemIterator::getFlags() basic tests
+--CREDITS--
+Joshua Thijssen <jthijssen@noxlogic.nl>
+--FILE--
+<?php
+
+$it = new FileSystemIterator(".");
+printflags($it);
+
+$it->setFlags(FileSystemIterator::CURRENT_AS_SELF |
+ FileSystemIterator::KEY_AS_FILENAME |
+ FileSystemIterator::SKIP_DOTS |
+ FileSystemIterator::UNIX_PATHS);
+printflags($it);
+
+$it->setFlags(-1);
+printflags($it);
+
+function printflags($it) {
+ printf("%08X\n", $it->getFlags());
+ printf("%08X\n", ($it->getFlags() & FileSystemIterator::CURRENT_MODE_MASK));
+ printf("%08X\n", ($it->getFlags() & FileSystemIterator::KEY_MODE_MASK));
+ printf("%08X\n", ($it->getFlags() & FileSystemIterator::OTHER_MODE_MASK));
+}
+
+?>
+--EXPECT--
+00001000
+00000000
+00000000
+00001000
+00003110
+00000010
+00000100
+00003000
+00003FF0
+000000F0
+00000F00
+00003000
diff --git a/ext/spl/tests/fixedarray_001.phpt b/ext/spl/tests/fixedarray_001.phpt
new file mode 100644
index 0000000..8276333
--- /dev/null
+++ b/ext/spl/tests/fixedarray_001.phpt
@@ -0,0 +1,60 @@
+--TEST--
+SPL: FixedArray: std operations
+--FILE--
+<?php
+$a = new SplFixedArray(0);
+// errors
+try {
+ $a[0] = "value1";
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($a["asdf"]);
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ unset($a[-1]);
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+$a->setSize(10);
+
+
+$a[0] = "value0";
+$a[1] = "value1";
+$a[2] = "value2";
+$a[3] = "value3";
+$ref = "value4";
+$ref2 =&$ref;
+$a[4] = $ref;
+$ref = "value5";
+
+unset($a[1]);
+
+var_dump($a[0], $a[2], $a[3], $a[4]);
+
+// countable
+
+var_dump(count($a), $a->getSize(), count($a) == $a->getSize());
+
+// clonable
+$b = clone $a;
+$a[0] = "valueNew";
+var_dump($b[0]);
+?>
+===DONE===
+--EXPECTF--
+Exception: Index invalid or out of range
+Exception: Index invalid or out of range
+Exception: Index invalid or out of range
+string(6) "value0"
+string(6) "value2"
+string(6) "value3"
+string(6) "value4"
+int(10)
+int(10)
+bool(true)
+string(6) "value0"
+===DONE===
diff --git a/ext/spl/tests/fixedarray_002.phpt b/ext/spl/tests/fixedarray_002.phpt
new file mode 100644
index 0000000..534d41f
--- /dev/null
+++ b/ext/spl/tests/fixedarray_002.phpt
@@ -0,0 +1,100 @@
+--TEST--
+SPL: FixedArray: overloading
+--FILE--
+<?php
+class A extends SplFixedArray {
+ public function count() {
+ return 2;
+ }
+
+ public function offsetGet($n) {
+ echo "A::offsetGet\n";
+ return parent::offsetGet($n);
+ }
+ public function offsetSet($n, $v) {
+ echo "A::offsetSet\n";
+ return parent::offsetSet($n, $v);
+ }
+ public function offsetUnset($n) {
+ echo "A::offsetUnset\n";
+ return parent::offsetUnset($n);
+ }
+ public function offsetExists($n) {
+ echo "A::offsetExists\n";
+ return parent::offsetExists($n);
+ }
+}
+
+$a = new A;
+
+// errors
+try {
+ $a[0] = "value1";
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($a["asdf"]);
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ unset($a[-1]);
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+$a->setSize(10);
+
+
+$a[0] = "value0";
+$a[1] = "value1";
+$a[2] = "value2";
+$a[3] = "value3";
+$ref = "value4";
+$ref2 =&$ref;
+$a[4] = $ref;
+$ref = "value5";
+
+unset($a[1]);
+var_dump(isset($a[1]), isset($a[2]), empty($a[1]), empty($a[2]));
+
+var_dump($a[0], $a[2], $a[3], $a[4]);
+
+// countable
+
+var_dump(count($a), $a->getSize(), count($a) == $a->getSize());
+?>
+===DONE===
+--EXPECTF--
+A::offsetSet
+Exception: Index invalid or out of range
+A::offsetGet
+Exception: Index invalid or out of range
+A::offsetUnset
+Exception: Index invalid or out of range
+A::offsetSet
+A::offsetSet
+A::offsetSet
+A::offsetSet
+A::offsetSet
+A::offsetUnset
+A::offsetExists
+A::offsetExists
+A::offsetExists
+A::offsetExists
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+A::offsetGet
+A::offsetGet
+A::offsetGet
+A::offsetGet
+string(6) "value0"
+string(6) "value2"
+string(6) "value3"
+string(6) "value4"
+int(2)
+int(10)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/fixedarray_003.phpt b/ext/spl/tests/fixedarray_003.phpt
new file mode 100644
index 0000000..b6c5eb5
--- /dev/null
+++ b/ext/spl/tests/fixedarray_003.phpt
@@ -0,0 +1,86 @@
+--TEST--
+SPL: FixedArray: Iterators
+--FILE--
+<?php
+class A extends SplFixedArray {
+
+ public function current() {
+ echo "A::current\n";
+ return parent::current();
+ }
+ public function key() {
+ echo "A::key\n";
+ return parent::key();
+ }
+ public function rewind() {
+ echo "A::rewind\n";
+ return parent::rewind();
+ }
+ public function valid() {
+ echo "A::valid\n";
+ return parent::valid();
+ }
+ public function next() {
+ echo "A::next\n";
+ return parent::next();
+ }
+}
+
+echo "==Direct instance==\n";
+$a = new SplFixedArray(5);
+$a[0] = "a";
+$a[1] = "c";
+$a[2] = "d";
+$a[3] = "e";
+$a[4] = "f";
+foreach ($a as $k => $v) {
+ echo "$k => $v\n";
+}
+echo "==Child instance==\n";
+$a = new A(5);
+$a[0] = "a";
+$a[1] = "c";
+$a[2] = "d";
+$a[3] = "e";
+$a[4] = "f";
+foreach ($a as $k => $v) {
+ echo "$k => $v\n";
+}
+?>
+===DONE===
+--EXPECTF--
+==Direct instance==
+0 => a
+1 => c
+2 => d
+3 => e
+4 => f
+==Child instance==
+A::rewind
+A::valid
+A::current
+A::key
+0 => a
+A::next
+A::valid
+A::current
+A::key
+1 => c
+A::next
+A::valid
+A::current
+A::key
+2 => d
+A::next
+A::valid
+A::current
+A::key
+3 => e
+A::next
+A::valid
+A::current
+A::key
+4 => f
+A::next
+A::valid
+===DONE===
diff --git a/ext/spl/tests/fixedarray_004.phpt b/ext/spl/tests/fixedarray_004.phpt
new file mode 100644
index 0000000..cb62e0c
--- /dev/null
+++ b/ext/spl/tests/fixedarray_004.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: FixedArray: adding new elements
+--FILE--
+<?php
+
+$a = new SplFixedArray(10);
+
+try {
+ $a[] = 1;
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+?>
+===DONE===
+--EXPECTF--
+string(29) "Index invalid or out of range"
+===DONE===
diff --git a/ext/spl/tests/fixedarray_005.phpt b/ext/spl/tests/fixedarray_005.phpt
new file mode 100644
index 0000000..9ccc693
--- /dev/null
+++ b/ext/spl/tests/fixedarray_005.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: FixedArray: Trying to instantiate passing object to constructor parameter
+--FILE--
+<?php
+
+$b = new stdClass;
+
+$a = new SplFixedArray($b);
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, object given in %s on line %d
diff --git a/ext/spl/tests/fixedarray_006.phpt b/ext/spl/tests/fixedarray_006.phpt
new file mode 100644
index 0000000..8641821
--- /dev/null
+++ b/ext/spl/tests/fixedarray_006.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: FixedArray: Assigning objects
+--FILE--
+<?php
+
+$b = 10000;
+$a = new SplFixedArray($b);
+
+try {
+ for ($i = 0; $i < 100; $i++) {
+ $a[] = new stdClass;
+ }
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+print "ok\n";
+
+?>
+--EXPECT--
+Index invalid or out of range
+ok
diff --git a/ext/spl/tests/fixedarray_007.phpt b/ext/spl/tests/fixedarray_007.phpt
new file mode 100644
index 0000000..308ce31
--- /dev/null
+++ b/ext/spl/tests/fixedarray_007.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: FixedArray: Assigning the itself object
+--FILE--
+<?php
+
+$b = 10;
+$a = new SplFixedArray($b);
+
+try {
+ $a[1] = $a;
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+foreach ($a as $c) {
+ if ($c) {
+ echo $c->getSize(), "\n";
+ }
+}
+
+print "ok\n";
+
+?>
+--EXPECT--
+10
+ok
diff --git a/ext/spl/tests/fixedarray_008.phpt b/ext/spl/tests/fixedarray_008.phpt
new file mode 100644
index 0000000..8775d61
--- /dev/null
+++ b/ext/spl/tests/fixedarray_008.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: FixedArray: Assigning the itself object testing the reference
+--FILE--
+<?php
+
+$b = 3;
+$a = new SplFixedArray($b);
+
+$a[0] = 1;
+$a[1] = 2;
+$a[2] = $a;
+
+$a[2][0] = 3;
+
+foreach ($a as $x) {
+ if (is_object($x)) {
+ var_dump($x[0]);
+ } else {
+ var_dump($x);
+ }
+}
+
+var_dump($a->getSize());
+
+?>
+--EXPECT--
+int(3)
+int(2)
+int(3)
+int(3)
diff --git a/ext/spl/tests/fixedarray_009.phpt b/ext/spl/tests/fixedarray_009.phpt
new file mode 100644
index 0000000..936d210
--- /dev/null
+++ b/ext/spl/tests/fixedarray_009.phpt
@@ -0,0 +1,10 @@
+--TEST--
+SPL: FixedArray: Trying to instantiate passing string to construtor parameter
+--FILE--
+<?php
+
+$a = new SplFixedArray('FOO');
+
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, string given in %s on line %d
diff --git a/ext/spl/tests/fixedarray_010.phpt b/ext/spl/tests/fixedarray_010.phpt
new file mode 100644
index 0000000..472e8b0
--- /dev/null
+++ b/ext/spl/tests/fixedarray_010.phpt
@@ -0,0 +1,50 @@
+--TEST--
+SPL: FixedArray: Setting size
+--FILE--
+<?php
+
+$a = new SplFixedArray(0);
+$a = new SplFixedArray(3);
+
+$a[0] = 1;
+
+$a->setSize(2);
+$a->setSize(3);
+$a->setSize(0);
+
+$a = new SplFixedArray(0);
+$a->setSize(0);
+var_dump($a->getSize());
+
+$a = new SplFixedArray(10);
+$a->setSize(10);
+var_dump($a->getSize());
+
+$a = new SplFixedArray(1);
+$a->setSize(5);
+var_dump($a->getSize());
+
+$a = new SplFixedArray(20);
+$a->setSize(3);
+var_dump($a->getSize());
+
+$a = new SplFixedArray(3);
+
+$a[0] = "test";
+$a[1] = array(1,2,"blah");
+$a[2] = 1;
+$a[0] = "test";
+
+$a->setSize(0);
+var_dump($a->getSize());
+
+print "ok\n";
+
+?>
+--EXPECT--
+int(0)
+int(10)
+int(5)
+int(3)
+int(0)
+ok
diff --git a/ext/spl/tests/fixedarray_011.phpt b/ext/spl/tests/fixedarray_011.phpt
new file mode 100644
index 0000000..eddf320
--- /dev/null
+++ b/ext/spl/tests/fixedarray_011.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: FixedArray: Testing setSize() with NULL
+--FILE--
+<?php
+
+$a = new SplFixedArray(100);
+
+$a->setSize(NULL);
+
+print "ok\n";
+
+?>
+--EXPECT--
+ok
diff --git a/ext/spl/tests/fixedarray_012.phpt b/ext/spl/tests/fixedarray_012.phpt
new file mode 100644
index 0000000..3461b3a
--- /dev/null
+++ b/ext/spl/tests/fixedarray_012.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: FixedArray: Assigning the object to another variable using []
+--FILE--
+<?php
+
+$a = new SplFixedArray(100);
+
+try {
+ $b = &$a[];
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+print "ok\n";
+
+?>
+--EXPECT--
+Index invalid or out of range
+ok
diff --git a/ext/spl/tests/fixedarray_013.phpt b/ext/spl/tests/fixedarray_013.phpt
new file mode 100644
index 0000000..52ae3c1
--- /dev/null
+++ b/ext/spl/tests/fixedarray_013.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: FixedArray: Passing the object using [] as parameter
+--FILE--
+<?php
+
+$a = new SplFixedArray(100);
+
+
+function test(SplFixedArray &$arr) {
+ print "ok\n";
+}
+
+try {
+ test($a[]);
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Index invalid or out of range
diff --git a/ext/spl/tests/fixedarray_014.phpt b/ext/spl/tests/fixedarray_014.phpt
new file mode 100644
index 0000000..de8e214
--- /dev/null
+++ b/ext/spl/tests/fixedarray_014.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: FixedArray: Trying to access inexistent item
+--FILE--
+<?php
+
+try {
+ $a = new SplFixedArray(NULL);
+ echo $a[0]++;
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Index invalid or out of range
diff --git a/ext/spl/tests/fixedarray_015.phpt b/ext/spl/tests/fixedarray_015.phpt
new file mode 100644
index 0000000..60fc4d1
--- /dev/null
+++ b/ext/spl/tests/fixedarray_015.phpt
@@ -0,0 +1,49 @@
+--TEST--
+SPL: FixedArray: accessing uninitialized array
+--FILE--
+<?php
+
+$a = new SplFixedArray('');
+
+try {
+ var_dump($a[1]);
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ $a[1] = 1;
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(count($a[1]));
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump($a->getSize());
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ foreach ($a as $v) {
+ }
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump($a->setSize(10));
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Warning: SplFixedArray::__construct() expects parameter 1 to be long, string given in %s on line %d
+Index invalid or out of range
+Index invalid or out of range
+Index invalid or out of range
+int(0)
+bool(true)
+Done
diff --git a/ext/spl/tests/fixedarray_016.phpt b/ext/spl/tests/fixedarray_016.phpt
new file mode 100644
index 0000000..fb61ee3
--- /dev/null
+++ b/ext/spl/tests/fixedarray_016.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: FixedArray: var_dump
+--FILE--
+<?php
+$a = new SplFixedArray(2);
+$a[0] = "foo";
+var_dump(empty($a[0]), empty($a[1]), $a);
+?>
+--EXPECTF--
+bool(false)
+bool(true)
+object(SplFixedArray)#%d (2) {
+ [0]=>
+ string(3) "foo"
+ [1]=>
+ NULL
+}
diff --git a/ext/spl/tests/fixedarray_017.phpt b/ext/spl/tests/fixedarray_017.phpt
new file mode 100644
index 0000000..fb61ee3
--- /dev/null
+++ b/ext/spl/tests/fixedarray_017.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: FixedArray: var_dump
+--FILE--
+<?php
+$a = new SplFixedArray(2);
+$a[0] = "foo";
+var_dump(empty($a[0]), empty($a[1]), $a);
+?>
+--EXPECTF--
+bool(false)
+bool(true)
+object(SplFixedArray)#%d (2) {
+ [0]=>
+ string(3) "foo"
+ [1]=>
+ NULL
+}
diff --git a/ext/spl/tests/fixedarray_018.phpt b/ext/spl/tests/fixedarray_018.phpt
new file mode 100644
index 0000000..84ab109
--- /dev/null
+++ b/ext/spl/tests/fixedarray_018.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: FixedArray: overriden count()
+--FILE--
+<?php
+$obj = new SplFixedArray(2);
+var_dump(count($obj));
+class SplFixedArray2 extends SplFixedArray {
+ public function count() {
+ return -parent::count();
+ }
+}
+$obj = new SplFixedArray2(2);
+var_dump(count($obj));
+?>
+--EXPECT--
+int(2)
+int(-2)
diff --git a/ext/spl/tests/fixedarray_019.phpt b/ext/spl/tests/fixedarray_019.phpt
new file mode 100644
index 0000000..f28edfd
--- /dev/null
+++ b/ext/spl/tests/fixedarray_019.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: FixedArray: overriden iterator methods
+--FILE--
+<?php
+class SplFixedArray2 extends SplFixedArray {
+ public function rewind() {
+ echo "rewind\n";
+ return parent::rewind();
+ }
+ public function valid() {
+ echo "valid\n";
+ return parent::valid();
+ }
+ public function next() {
+ echo "next\n";
+ return parent::next();
+ }
+ public function current() {
+ echo "current\n";
+ return parent::current();
+ }
+ public function key() {
+ echo "key\n";
+ return parent::key();
+ }
+}
+
+$fa = new SplFixedArray2(3);
+foreach($fa as $k=>$v) {
+ echo "$k=>";
+ var_dump($v);
+}
+?>
+--EXPECT--
+rewind
+valid
+current
+key
+0=>NULL
+next
+valid
+current
+key
+1=>NULL
+next
+valid
+current
+key
+2=>NULL
+next
+valid
diff --git a/ext/spl/tests/fixedarray_020.phpt b/ext/spl/tests/fixedarray_020.phpt
new file mode 100644
index 0000000..c0ff6e3
--- /dev/null
+++ b/ext/spl/tests/fixedarray_020.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: FixedArray: fromArray/toArray + get_properties
+--FILE--
+<?php
+$a = array(1=>'foo', 2=>'bar', 0=>'gee');
+$fa = SplFixedArray::fromArray($a, false);
+var_dump(count($fa), $fa->toArray() === array_values($a));
+
+$fa = SplFixedArray::fromArray($a, true);
+var_dump(count($fa), $fa->toArray() === $a, $fa->toArray() === (array)$fa);
+
+try {
+ echo "From Array with string keys, no preserve\n";
+ SplFixedArray::fromArray(array("foo"=>"bar"), false);
+ echo "No exception\n";
+} catch (Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ echo "From Array with string keys, preserve\n";
+ SplFixedArray::fromArray(array("foo"=>"bar"), true);
+ echo "No exception\n";
+} catch (Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+--EXPECT--
+int(3)
+bool(true)
+int(3)
+bool(false)
+bool(true)
+From Array with string keys, no preserve
+No exception
+From Array with string keys, preserve
+Exception: array must contain only positive integer keys
diff --git a/ext/spl/tests/fixedarray_021.phpt b/ext/spl/tests/fixedarray_021.phpt
new file mode 100644
index 0000000..97b0a70
--- /dev/null
+++ b/ext/spl/tests/fixedarray_021.phpt
@@ -0,0 +1,78 @@
+--TEST--
+SPL: FixedArray: misc small tests
+--FILE--
+<?php
+
+/* empty count */
+$a = new SplFixedArray();
+
+var_dump(count($a));
+var_dump($a->count());
+
+/* negative init value */
+try {
+ $b = new SplFixedArray(-10);
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+/* resize and negative value */
+$b = new SplFixedArray();
+try {
+ $b->setSize(-5);
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+/* calling __construct() twice */
+$c = new SplFixedArray(0);
+var_dump($c->__construct());
+
+/* fromArray() from empty array */
+$d = new SplFixedArray();
+$d->fromArray(array());
+
+var_dump(count($a));
+var_dump($a->count());
+var_dump($a);
+
+/* foreach by ref */
+$e = new SplFixedArray(10);
+$e[0] = 1;
+$e[1] = 5;
+$e[2] = 10;
+
+try {
+ foreach ($e as $k=>&$v) {
+ var_dump($v);
+ }
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+//non-long indexes
+$a = new SplFixedArray(4);
+$a["2"] = "foo";
+$a["1"] = "foo";
+$a["3"] = "0";
+
+var_dump(isset($a["0"], $a[-1]), $a["1"]);
+var_dump(empty($a["3"]));
+
+?>
+==DONE==
+--EXPECTF--
+int(0)
+int(0)
+string(35) "array size cannot be less than zero"
+string(35) "array size cannot be less than zero"
+NULL
+int(0)
+int(0)
+object(SplFixedArray)#%d (0) {
+}
+string(52) "An iterator cannot be used with foreach by reference"
+bool(false)
+string(3) "foo"
+bool(true)
+==DONE==
diff --git a/ext/spl/tests/heap_001.phpt b/ext/spl/tests/heap_001.phpt
new file mode 100644
index 0000000..da4dde8
--- /dev/null
+++ b/ext/spl/tests/heap_001.phpt
@@ -0,0 +1,53 @@
+--TEST--
+SPL: SplMaxHeap: std operations
+--FILE--
+<?php
+$h = new SplMaxHeap();
+
+// errors
+try {
+ $h->extract();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+
+$h->insert(1);
+$h->insert(2);
+$h->insert(3);
+$h->insert(3);
+$h->insert(3);
+
+echo $h->count()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->count()."\n";
+
+echo "--\n";
+
+$b = 4;
+$h->insert($b);
+$b = 5;
+
+$h2 = clone $h;
+echo $h->extract()."\n";
+echo $h2->extract()."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't extract from an empty heap
+5
+3
+3
+3
+2
+1
+0
+--
+4
+4
+===DONE===
diff --git a/ext/spl/tests/heap_002.phpt b/ext/spl/tests/heap_002.phpt
new file mode 100644
index 0000000..387510f
--- /dev/null
+++ b/ext/spl/tests/heap_002.phpt
@@ -0,0 +1,50 @@
+--TEST--
+SPL: SplMinHeap: std operations
+--FILE--
+<?php
+$h = new SplMinHeap();
+
+// errors
+try {
+ $h->extract();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+
+$h->insert(1);
+$h->insert(2);
+$h->insert(3);
+$h->insert(3);
+$h->insert(3);
+
+echo $h->count()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->extract()."\n";
+echo $h->count()."\n";
+
+echo "--\n";
+
+$b = 4;
+$h->insert($b);
+$b = 5;
+
+echo $h->extract()."\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't extract from an empty heap
+5
+1
+2
+3
+3
+3
+0
+--
+4
+===DONE===
diff --git a/ext/spl/tests/heap_003.phpt b/ext/spl/tests/heap_003.phpt
new file mode 100644
index 0000000..87f95e9
--- /dev/null
+++ b/ext/spl/tests/heap_003.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: SplHeap: comparison callback
+--FILE--
+<?php
+class myHeap extends SplHeap {
+ public function compare($a, $b) {
+ if ($a > $b) {
+ $result = 1;
+ } else if ($a < $b) {
+ $result = -1;
+ } else {
+ $result = 0;
+ }
+ return $result;
+ }
+}
+
+$h = new myHeap;
+
+$in = range(0,10);
+shuffle($in);
+foreach ($in as $i) {
+ $h->insert($i);
+}
+
+foreach ($h as $out) {
+ echo $out."\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+10
+9
+8
+7
+6
+5
+4
+3
+2
+1
+0
+===DONE===
diff --git a/ext/spl/tests/heap_004.phpt b/ext/spl/tests/heap_004.phpt
new file mode 100644
index 0000000..7b00ebf
--- /dev/null
+++ b/ext/spl/tests/heap_004.phpt
@@ -0,0 +1,67 @@
+--TEST--
+SPL: SplHeap: exceptions
+--FILE--
+<?php
+class myHeap extends SplHeap {
+ public function compare($a, $b) {
+ throw new exception("foo");
+ }
+}
+
+$h = new myHeap;
+
+try {
+ $h->insert(1);
+ echo "inserted 1\n";
+ $h->insert(2);
+ echo "inserted 2\n";
+ $h->insert(3);
+ echo "inserted 3\n";
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ $h->insert(4);
+ echo "inserted 4\n";
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+echo "Recovering..\n";
+$h->recoverFromCorruption();
+
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+inserted 1
+Exception: foo
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Recovering..
+int(1)
+int(2)
+===DONE===
diff --git a/ext/spl/tests/heap_005.phpt b/ext/spl/tests/heap_005.phpt
new file mode 100644
index 0000000..1291cda
--- /dev/null
+++ b/ext/spl/tests/heap_005.phpt
@@ -0,0 +1,121 @@
+--TEST--
+SPL: SplMinHeap: large unordered input iterated
+--FILE--
+<?php
+$input = range(1,100);
+shuffle($input);
+
+$h = new SplMinHeap();
+
+foreach($input as $i) {
+ $h->insert($i);
+}
+
+foreach ($h as $k => $o) {
+ echo "$k => $o\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+99 => 1
+98 => 2
+97 => 3
+96 => 4
+95 => 5
+94 => 6
+93 => 7
+92 => 8
+91 => 9
+90 => 10
+89 => 11
+88 => 12
+87 => 13
+86 => 14
+85 => 15
+84 => 16
+83 => 17
+82 => 18
+81 => 19
+80 => 20
+79 => 21
+78 => 22
+77 => 23
+76 => 24
+75 => 25
+74 => 26
+73 => 27
+72 => 28
+71 => 29
+70 => 30
+69 => 31
+68 => 32
+67 => 33
+66 => 34
+65 => 35
+64 => 36
+63 => 37
+62 => 38
+61 => 39
+60 => 40
+59 => 41
+58 => 42
+57 => 43
+56 => 44
+55 => 45
+54 => 46
+53 => 47
+52 => 48
+51 => 49
+50 => 50
+49 => 51
+48 => 52
+47 => 53
+46 => 54
+45 => 55
+44 => 56
+43 => 57
+42 => 58
+41 => 59
+40 => 60
+39 => 61
+38 => 62
+37 => 63
+36 => 64
+35 => 65
+34 => 66
+33 => 67
+32 => 68
+31 => 69
+30 => 70
+29 => 71
+28 => 72
+27 => 73
+26 => 74
+25 => 75
+24 => 76
+23 => 77
+22 => 78
+21 => 79
+20 => 80
+19 => 81
+18 => 82
+17 => 83
+16 => 84
+15 => 85
+14 => 86
+13 => 87
+12 => 88
+11 => 89
+10 => 90
+9 => 91
+8 => 92
+7 => 93
+6 => 94
+5 => 95
+4 => 96
+3 => 97
+2 => 98
+1 => 99
+0 => 100
+===DONE===
diff --git a/ext/spl/tests/heap_006.phpt b/ext/spl/tests/heap_006.phpt
new file mode 100644
index 0000000..3218bdf
--- /dev/null
+++ b/ext/spl/tests/heap_006.phpt
@@ -0,0 +1,121 @@
+--TEST--
+SPL: SplMaxHeap: large unordered input iterated
+--FILE--
+<?php
+$input = range(1,100);
+shuffle($input);
+
+$h = new SplMaxHeap();
+
+foreach($input as $i) {
+ $h->insert($i);
+}
+
+foreach ($h as $k => $o) {
+ echo "$k => $o\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+99 => 100
+98 => 99
+97 => 98
+96 => 97
+95 => 96
+94 => 95
+93 => 94
+92 => 93
+91 => 92
+90 => 91
+89 => 90
+88 => 89
+87 => 88
+86 => 87
+85 => 86
+84 => 85
+83 => 84
+82 => 83
+81 => 82
+80 => 81
+79 => 80
+78 => 79
+77 => 78
+76 => 77
+75 => 76
+74 => 75
+73 => 74
+72 => 73
+71 => 72
+70 => 71
+69 => 70
+68 => 69
+67 => 68
+66 => 67
+65 => 66
+64 => 65
+63 => 64
+62 => 63
+61 => 62
+60 => 61
+59 => 60
+58 => 59
+57 => 58
+56 => 57
+55 => 56
+54 => 55
+53 => 54
+52 => 53
+51 => 52
+50 => 51
+49 => 50
+48 => 49
+47 => 48
+46 => 47
+45 => 46
+44 => 45
+43 => 44
+42 => 43
+41 => 42
+40 => 41
+39 => 40
+38 => 39
+37 => 38
+36 => 37
+35 => 36
+34 => 35
+33 => 34
+32 => 33
+31 => 32
+30 => 31
+29 => 30
+28 => 29
+27 => 28
+26 => 27
+25 => 26
+24 => 25
+23 => 24
+22 => 23
+21 => 22
+20 => 21
+19 => 20
+18 => 19
+17 => 18
+16 => 17
+15 => 16
+14 => 15
+13 => 14
+12 => 13
+11 => 12
+10 => 11
+9 => 10
+8 => 9
+7 => 8
+6 => 7
+5 => 6
+4 => 5
+3 => 4
+2 => 3
+1 => 2
+0 => 1
+===DONE===
diff --git a/ext/spl/tests/heap_007.phpt b/ext/spl/tests/heap_007.phpt
new file mode 100644
index 0000000..e8d5c99
--- /dev/null
+++ b/ext/spl/tests/heap_007.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: SplHeap: iteration through methods
+--FILE--
+<?php
+$h = new SplMaxHeap();
+
+$h->insert(1);
+$h->insert(5);
+$h->insert(0);
+$h->insert(4);
+
+$h->rewind();
+echo "count(\$h) = ".count($h)."\n";
+echo "\$h->count() = ".$h->count()."\n";
+
+while ($h->valid()) {
+ $k = $h->key();
+ $v = $h->current();
+ echo "$k=>$v\n";
+ $h->next();
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+count($h) = 4
+$h->count() = 4
+3=>5
+2=>4
+1=>1
+0=>0
+===DONE===
diff --git a/ext/spl/tests/heap_008.phpt b/ext/spl/tests/heap_008.phpt
new file mode 100644
index 0000000..178f546
--- /dev/null
+++ b/ext/spl/tests/heap_008.phpt
@@ -0,0 +1,34 @@
+--TEST--
+SPL: SplHeap: var_dump
+--FILE--
+<?php
+$h = new SplMaxHeap();
+
+$h->insert(1);
+$h->insert(5);
+$h->insert(0);
+$h->insert(4);
+
+var_dump($h);
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(SplMaxHeap)#1 (3) {
+ ["flags":"SplHeap":private]=>
+ int(0)
+ ["isCorrupted":"SplHeap":private]=>
+ bool(false)
+ ["heap":"SplHeap":private]=>
+ array(4) {
+ [0]=>
+ int(5)
+ [1]=>
+ int(4)
+ [2]=>
+ int(0)
+ [3]=>
+ int(1)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/heap_009.phpt b/ext/spl/tests/heap_009.phpt
new file mode 100644
index 0000000..f660b24
--- /dev/null
+++ b/ext/spl/tests/heap_009.phpt
@@ -0,0 +1,56 @@
+--TEST--
+SPL: SplHeap and friends, throw: An iterator cannot be used with foreach by reference
+--CREDITS--
+Thomas Koch <thomas@koch.ro>
+#Hackday Webtuesday 2008-05-24
+--FILE--
+<?php
+function testForException( $heap )
+{
+ try
+ {
+ foreach( $heap as &$item );
+ }
+ catch( RuntimeException $e )
+ {
+ echo $e->getMessage(),"\n";
+ }
+}
+
+// 1. SplMinHeap emtpy
+$heap = new SplMinHeap;
+testForException( $heap );
+
+// 2. SplMinHeap non-emtpy
+$heap = new SplMinHeap;
+$heap->insert( 1 );
+testForException( $heap );
+
+// 3. SplMaxHeap emtpy
+$heap = new SplMaxHeap;
+testForException( $heap );
+
+// 4. SplMaxHeap non-emtpy
+$heap = new SplMaxHeap;
+$heap->insert( 1 );
+testForException( $heap );
+
+// 5. SplPriorityQueue empty
+$heap = new SplPriorityQueue;
+testForException( $heap );
+
+// 6. SplPriorityQueue non-empty
+$heap = new SplPriorityQueue;
+$heap->insert( 1, 2 );
+testForException( $heap );
+
+?>
+==DONE==
+--EXPECT--
+An iterator cannot be used with foreach by reference
+An iterator cannot be used with foreach by reference
+An iterator cannot be used with foreach by reference
+An iterator cannot be used with foreach by reference
+An iterator cannot be used with foreach by reference
+An iterator cannot be used with foreach by reference
+==DONE==
diff --git a/ext/spl/tests/heap_010.phpt b/ext/spl/tests/heap_010.phpt
new file mode 100644
index 0000000..8c7d8d5
--- /dev/null
+++ b/ext/spl/tests/heap_010.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: SplHeap with overriden count()
+--FILE--
+<?php
+$obj = new SplMaxHeap();
+$obj->insert(1);
+$obj->insert(2);
+var_dump(count($obj));
+class SplMaxHeap2 extends SplMaxHeap{
+ public function count() {
+ return -parent::count();
+ }
+}
+$obj = new SplMaxHeap2();
+$obj->insert(1);
+$obj->insert(2);
+var_dump(count($obj));
+?>
+--EXPECT--
+int(2)
+int(-2)
diff --git a/ext/spl/tests/heap_011.phpt b/ext/spl/tests/heap_011.phpt
new file mode 100644
index 0000000..1689abf
--- /dev/null
+++ b/ext/spl/tests/heap_011.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplHeap with overriden compare()
+--FILE--
+<?php
+class SplMinHeap2 extends SplMinHeap {
+ public function compare($a, $b) {
+ return -parent::compare($a,$b);
+ }
+}
+$h = new SplMinHeap2();
+$h->insert(1);
+$h->insert(6);
+$h->insert(5);
+$h->insert(2);
+var_dump($h->top());
+
+class SplMaxHeap2 extends SplMaxHeap {
+ public function compare($a, $b) {
+ return -parent::compare($a,$b);
+ }
+}
+$h = new SplMaxHeap2();
+$h->insert(1);
+$h->insert(6);
+$h->insert(5);
+$h->insert(2);
+var_dump($h->top());
+?>
+--EXPECT--
+int(6)
+int(1)
diff --git a/ext/spl/tests/heap_012.phpt b/ext/spl/tests/heap_012.phpt
new file mode 100644
index 0000000..f86f14f
--- /dev/null
+++ b/ext/spl/tests/heap_012.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplHeap recursive var_dump
+--FILE--
+<?php
+$a = new SplMaxHeap;
+$a->insert($a);
+var_dump($a)
+?>
+===DONE===
+--EXPECTF--
+object(SplMaxHeap)#%d (3) {
+ ["flags":"SplHeap":private]=>
+ int(0)
+ ["isCorrupted":"SplHeap":private]=>
+ bool(false)
+ ["heap":"SplHeap":private]=>
+ array(1) {
+ [0]=>
+ *RECURSION*
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/heap_corruption.phpt b/ext/spl/tests/heap_corruption.phpt
new file mode 100644
index 0000000..284ee1d
--- /dev/null
+++ b/ext/spl/tests/heap_corruption.phpt
@@ -0,0 +1,62 @@
+--TEST--
+SPL: SplHeap - heap corruption via compare exception (with top element deletion)
+--CREDITS--
+Mike Sullivan <mikesul@php.net>
+#TestFest 2009 (London)
+--FILE--
+<?php
+
+class myHeap extends SplHeap
+{
+ public $allow_compare = true;
+
+ public function compare($v1, $v2)
+ {
+ if ($this->allow_compare == true)
+ {
+ if ($v1 > $v2)
+ {
+ return 1;
+ }
+ else if ($v1 < $v2)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ throw new Exception('Compare exception');
+ }
+ }
+}
+
+$heap = new myHeap();
+$heap->insert(1);
+$heap->insert(2);
+$heap->insert(3);
+$heap->insert(4);
+
+$heap->allow_compare = false;
+
+try {
+ $heap->extract();
+}
+catch (Exception $e) {
+ echo "Compare Exception: " . $e->getMessage() . PHP_EOL;
+}
+
+try {
+ $heap->top();
+}
+catch (Exception $e) {
+ echo "Corruption Exception: " . $e->getMessage() . PHP_EOL;
+}
+
+?>
+--EXPECT--
+Compare Exception: Compare exception
+Corruption Exception: Heap is corrupted, heap properties are no longer ensured. \ No newline at end of file
diff --git a/ext/spl/tests/heap_current_variation_001.phpt b/ext/spl/tests/heap_current_variation_001.phpt
new file mode 100644
index 0000000..eb6df2b
--- /dev/null
+++ b/ext/spl/tests/heap_current_variation_001.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplHeap::current - get current value from empty heap
+--CREDITS--
+Mike Sullivan <mikesul@php.net>
+#TestFest 2009 (London)
+--FILE--
+<?php
+
+class myHeap extends SplHeap
+{
+ public function compare($v1, $v2)
+ {
+ throw new Exception('');
+ }
+}
+
+$heap = new myHeap();
+var_dump($heap->current());
+
+?>
+--EXPECT--
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/heap_isempty_variation_001.phpt b/ext/spl/tests/heap_isempty_variation_001.phpt
new file mode 100644
index 0000000..dac470f
--- /dev/null
+++ b/ext/spl/tests/heap_isempty_variation_001.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: SplHeap: isEmpty argument variation.
+--FILE--
+<?php
+class SplHeap2 extends SplHeap{
+
+ public function compare() {
+ return -parent::compare();
+ }
+}
+
+$h = new SplHeap2;
+$h->isEmpty(1);
+?>
+--EXPECTF--
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s
diff --git a/ext/spl/tests/heap_it_current_empty.phpt b/ext/spl/tests/heap_it_current_empty.phpt
new file mode 100644
index 0000000..24230db
--- /dev/null
+++ b/ext/spl/tests/heap_it_current_empty.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplHeap current, check looping through an empty heap gives you no values
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplMinHeap();
+
+foreach ($h as $val) { echo 'FAIL'; }
+?>
+--EXPECT--
diff --git a/ext/spl/tests/heap_top_variation_001.phpt b/ext/spl/tests/heap_top_variation_001.phpt
new file mode 100644
index 0000000..9953cf9
--- /dev/null
+++ b/ext/spl/tests/heap_top_variation_001.phpt
@@ -0,0 +1,14 @@
+--TEST--
+SPL: SplHeap top, illegal number of args
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplMinHeap();
+$h->insert(5);
+// top doesn't take any args, lets see what happens if we give it one
+$h->top('bogus');
+?>
+--EXPECTF--
+Warning: SplHeap::top() expects exactly 0 parameters, 1 given in %s
diff --git a/ext/spl/tests/heap_top_variation_002.phpt b/ext/spl/tests/heap_top_variation_002.phpt
new file mode 100644
index 0000000..cd6a8d0
--- /dev/null
+++ b/ext/spl/tests/heap_top_variation_002.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplHeap top, corrupted heap
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+// override heap to force corruption by throwing exception in compare
+class SplMinHeap2 extends SplMinHeap {
+ public function compare($a, $b) {
+ throw new Exception('Corrupt heap');
+ }
+}
+
+$h = new SplMinHeap2();
+
+// insert 2 elements to hit our overridden compare
+$h->insert(4);
+try {
+ $h->insert(5);
+} catch (Exception $e) {}
+
+// call top, should fail with corrupted heap
+try {
+ $h->top();
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECTF--
+Heap is corrupted, heap properties are no longer ensured.
diff --git a/ext/spl/tests/heap_top_variation_003.phpt b/ext/spl/tests/heap_top_variation_003.phpt
new file mode 100644
index 0000000..7a91a9c
--- /dev/null
+++ b/ext/spl/tests/heap_top_variation_003.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: SplHeap top of empty heap
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplMinHeap();
+try {
+ $h->top();
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECTF--
+Can't peek at an empty heap
diff --git a/ext/spl/tests/iterator_001.phpt b/ext/spl/tests/iterator_001.phpt
new file mode 100644
index 0000000..26df62e
--- /dev/null
+++ b/ext/spl/tests/iterator_001.phpt
@@ -0,0 +1,171 @@
+--TEST--
+SPL: Iterator aggregating inner iterator's methods
+--FILE--
+<?php
+
+class NumericArrayIterator implements Iterator
+{
+ protected $a;
+ protected $i = 0;
+
+ public function __construct($a)
+ {
+ echo __METHOD__ . "\n";
+ $this->a = $a;
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->i = 0;
+ }
+
+ public function valid()
+ {
+ $ret = $this->i < count($this->a);
+ echo __METHOD__ . '(' . ($ret ? 'true' : 'false') . ")\n";
+ return $ret;
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return $this->a[$this->i];
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->i++;
+ }
+
+ public function greaterThan($comp)
+ {
+ echo get_class($this) . '::' . __FUNCTION__ . '(' . $comp . ")\n";
+ return $this->current() > $comp;
+ }
+}
+
+class SeekableNumericArrayIterator extends NumericArrayIterator implements SeekableIterator
+{
+ public function seek($index)
+ {
+ if ($index < count($this->a)) {
+ $this->i = $index;
+ }
+ echo __METHOD__ . '(' . $index . ")\n";
+ }
+}
+
+$a = array(1, 2, 3, 4, 5);
+$it = new LimitIterator(new NumericArrayIterator($a), 1, 3);
+foreach ($it as $v)
+{
+ print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n";
+}
+
+echo "===SEEKABLE===\n";
+$a = array(1, 2, 3, 4, 5);
+$it = new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3);
+foreach($it as $v)
+{
+ print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n";
+}
+
+echo "===STACKED===\n";
+echo "Shows '2 is greater than 2' because the test is actually done with the current value which is 3.\n";
+$a = array(1, 2, 3, 4, 5);
+$it = new CachingIterator(new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3));
+foreach($it as $v)
+{
+ print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+NumericArrayIterator::valid(true)
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+NumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+2 is less than or equal 2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+NumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+3 is greater than 2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+NumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+4 is greater than 2
+NumericArrayIterator::next
+===SEEKABLE===
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+SeekableNumericArrayIterator::seek(1)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+2 is less than or equal 2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+3 is greater than 2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+4 is greater than 2
+NumericArrayIterator::next
+===STACKED===
+Shows '2 is greater than 2' because the test is actually done with the current value which is 3.
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+SeekableNumericArrayIterator::seek(1)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+2 is greater than 2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+3 is greater than 2
+NumericArrayIterator::next
+SeekableNumericArrayIterator::greaterThan(2)
+NumericArrayIterator::current
+4 is greater than 2
+===DONE===
diff --git a/ext/spl/tests/iterator_002.phpt b/ext/spl/tests/iterator_002.phpt
new file mode 100644
index 0000000..527fe6b
--- /dev/null
+++ b/ext/spl/tests/iterator_002.phpt
@@ -0,0 +1,55 @@
+--TEST--
+SPL: Iterator using getInnerIterator
+--FILE--
+<?php
+
+class RecursiceArrayIterator extends ArrayIterator implements RecursiveIterator
+{
+ function hasChildren()
+ {
+ return is_array($this->current());
+ }
+
+ function getChildren()
+ {
+ return new RecursiceArrayIterator($this->current());
+ }
+}
+
+class CrashIterator extends FilterIterator implements RecursiveIterator
+{
+ function accept()
+ {
+ return true;
+ }
+
+ function hasChildren()
+ {
+ return $this->getInnerIterator()->hasChildren();
+ }
+
+ function getChildren()
+ {
+ return new RecursiceArrayIterator($this->getInnerIterator()->current());
+ }
+}
+
+$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3);
+
+$dir = new RecursiveIteratorIterator(new CrashIterator(new RecursiceArrayIterator($array)), RecursiveIteratorIterator::LEAVES_ONLY);
+
+foreach ($dir as $file) {
+ print "$file\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1
+21
+221
+222
+231
+3
+===DONE===
diff --git a/ext/spl/tests/iterator_003.phpt b/ext/spl/tests/iterator_003.phpt
new file mode 100644
index 0000000..11d37b3
--- /dev/null
+++ b/ext/spl/tests/iterator_003.phpt
@@ -0,0 +1,95 @@
+--TEST--
+SPL: CachingIterator and __toString()
+--FILE--
+<?php
+
+class Student
+{
+ private $id;
+ private $name;
+
+ public function __construct($id, $name)
+ {
+ $this->id = $id;
+ $this->name = $name;
+ }
+
+ public function __toString()
+ {
+ return $this->id . ', ' . $this->name;
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+}
+
+class StudentIdFilter extends FilterIterator
+{
+ private $id;
+
+ public function __construct(ArrayObject $students, Student $other)
+ {
+ FilterIterator::__construct($students->getIterator());
+ $this->id = $other->getId();
+ }
+
+ public function accept()
+ {
+ echo "ACCEPT ".$this->current()->getId()." == ".$this->id."\n";
+ return $this->current()->getId() == $this->id;
+ }
+}
+
+class StudentList implements IteratorAggregate
+{
+ private $students;
+
+ public function __construct()
+ {
+ $this->students = new ArrayObject(array());
+ }
+
+ public function add(Student $student)
+ {
+ if (!$this->contains($student)) {
+ $this->students[] = $student;
+ }
+ }
+
+ public function contains(Student $student)
+ {
+ foreach ($this->students as $s)
+ {
+ if ($s->getId() == $student->getId()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function getIterator() {
+ return new CachingIterator($this->students->getIterator(), true);
+ }
+}
+
+$students = new StudentList();
+$students->add(new Student('01234123', 'Joe'));
+$students->add(new Student('00000014', 'Bob'));
+$students->add(new Student('00000014', 'Foo'));
+
+// The goal is to verify we can access the cached string value even if it was
+// generated by a call to __toString(). To check this we need to access the
+// iterator's __toString() method.
+$it = $students->getIterator();
+foreach ($it as $student) {
+ echo $it->__toString(), "\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+01234123, Joe
+00000014, Bob
+===DONE===
diff --git a/ext/spl/tests/iterator_004.phpt b/ext/spl/tests/iterator_004.phpt
new file mode 100644
index 0000000..e07cd32
--- /dev/null
+++ b/ext/spl/tests/iterator_004.phpt
@@ -0,0 +1,142 @@
+--TEST--
+SPL: SeekableIterator and string keys
+--FILE--
+<?php
+
+class NumericArrayIterator implements Iterator
+{
+ protected $a;
+ protected $i;
+
+ public function __construct($a)
+ {
+ echo __METHOD__ . "\n";
+ $this->a = $a;
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->i = 0;
+ }
+
+ public function valid()
+ {
+ $ret = $this->i < count($this->a);
+ echo __METHOD__ . '(' . ($ret ? 'true' : 'false') . ")\n";
+ return $ret;
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return $this->a[$this->i];
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->i++;
+ }
+}
+
+class SeekableNumericArrayIterator extends NumericArrayIterator implements SeekableIterator
+{
+ public function seek($index)
+ {
+ if ($index < count($this->a)) {
+ $this->i = $index;
+ }
+ echo __METHOD__ . '(' . $index . ")\n";
+ }
+}
+
+$a = array(1, 2, 3, 4, 5);
+foreach (new LimitIterator(new NumericArrayIterator($a), 1, 3) as $v)
+{
+ print "$v\n";
+}
+
+echo "===SEEKABLE===\n";
+$a = array(1, 2, 3, 4, 5);
+foreach(new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3) as $v)
+{
+ print "$v\n";
+}
+
+echo "===SEEKING===\n";
+$a = array(1, 2, 3, 4, 5);
+$l = new LimitIterator(new SeekableNumericArrayIterator($a));
+for($i = 1; $i < 4; $i++)
+{
+ $l->seek($i);
+ print $l->current() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+NumericArrayIterator::valid(true)
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+3
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+4
+NumericArrayIterator::next
+===SEEKABLE===
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+SeekableNumericArrayIterator::seek(1)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+2
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+3
+NumericArrayIterator::next
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+4
+NumericArrayIterator::next
+===SEEKING===
+NumericArrayIterator::__construct
+SeekableNumericArrayIterator::seek(1)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+2
+SeekableNumericArrayIterator::seek(2)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+3
+SeekableNumericArrayIterator::seek(3)
+NumericArrayIterator::valid(true)
+NumericArrayIterator::current
+NumericArrayIterator::key
+4
+===DONE===
diff --git a/ext/spl/tests/iterator_005.phpt b/ext/spl/tests/iterator_005.phpt
new file mode 100644
index 0000000..640ca9f
--- /dev/null
+++ b/ext/spl/tests/iterator_005.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: IteratorIterator and ArrayIterator/Object
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ return parent::rewind();
+ }
+}
+
+$it = new ArrayIteratorEx(range(0,3));
+
+foreach(new IteratorIterator($it) as $v)
+{
+ var_dump($v);
+}
+
+class ArrayObjectEx extends ArrayObject
+{
+ function getIterator()
+ {
+ echo __METHOD__ . "\n";
+ return parent::getIterator();
+ }
+}
+
+$it = new ArrayObjectEx(range(0,3));
+
+foreach(new IteratorIterator($it) as $v)
+{
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+ArrayIteratorEx::rewind
+int(0)
+int(1)
+int(2)
+int(3)
+ArrayObjectEx::getIterator
+int(0)
+int(1)
+int(2)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/iterator_006.phpt b/ext/spl/tests/iterator_006.phpt
new file mode 100644
index 0000000..54da89c
--- /dev/null
+++ b/ext/spl/tests/iterator_006.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: IteratorIterator and SimpleXMlElement
+--SKIPIF--
+<?php if (!extension_loaded('simplexml')) print "skip SimpleXML required"; ?>
+--FILE--
+<?php
+
+$root = simplexml_load_string(b'<?xml version="1.0"?>
+<root>
+ <child>Hello</child>
+ <child>World</child>
+</root>
+');
+
+foreach (new IteratorIterator($root->child) as $child) {
+ echo $child."\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+Hello
+World
+===DONE===
diff --git a/ext/spl/tests/iterator_007.phpt b/ext/spl/tests/iterator_007.phpt
new file mode 100644
index 0000000..d26c01e
--- /dev/null
+++ b/ext/spl/tests/iterator_007.phpt
@@ -0,0 +1,166 @@
+--TEST--
+SPL: NoRewindIterator
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+}
+
+class NoRewindIteratorEx extends NoRewindIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+}
+
+$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3)));
+
+echo "===0===\n";
+foreach ($it->getInnerIterator() as $v) {
+ var_dump($v);
+}
+
+echo "===1===\n";
+foreach ($it as $v) {
+ var_dump($v);
+}
+
+$pos =0;
+
+$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3)));
+
+echo "===2===\n";
+foreach ($it as $v) {
+ var_dump($v);
+ if ($pos++ > 1) {
+ break;
+ }
+}
+
+echo "===3===\n";
+foreach ($it as $v) {
+ var_dump($v);
+}
+
+echo "===4===\n";
+foreach ($it as $v) {
+ var_dump($v);
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===0===
+ArrayIteratorEx::rewind
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+int(0)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+int(1)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+int(2)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+int(3)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+===1===
+NoRewindIteratorEx::rewind
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+===2===
+NoRewindIteratorEx::rewind
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+NoRewindIteratorEx::current
+ArrayIteratorEx::current
+int(0)
+NoRewindIteratorEx::next
+ArrayIteratorEx::next
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+NoRewindIteratorEx::current
+ArrayIteratorEx::current
+int(1)
+NoRewindIteratorEx::next
+ArrayIteratorEx::next
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+NoRewindIteratorEx::current
+ArrayIteratorEx::current
+int(2)
+===3===
+NoRewindIteratorEx::rewind
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+NoRewindIteratorEx::current
+int(2)
+NoRewindIteratorEx::next
+ArrayIteratorEx::next
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+NoRewindIteratorEx::current
+ArrayIteratorEx::current
+int(3)
+NoRewindIteratorEx::next
+ArrayIteratorEx::next
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+===4===
+NoRewindIteratorEx::rewind
+NoRewindIteratorEx::valid
+ArrayIteratorEx::valid
+===DONE===
diff --git a/ext/spl/tests/iterator_008.phpt b/ext/spl/tests/iterator_008.phpt
new file mode 100644
index 0000000..04f8c00
--- /dev/null
+++ b/ext/spl/tests/iterator_008.phpt
@@ -0,0 +1,89 @@
+--TEST--
+SPL: InfiniteIterator
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+}
+
+$it = new InfiniteIterator(new ArrayIteratorEx(range(0,2)));
+
+$pos =0;
+
+foreach ($it as $v) {
+ var_dump($v);
+ if ($pos++ > 5) {
+ break;
+ }
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+ArrayIteratorEx::rewind
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(0)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(1)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(2)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::rewind
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(0)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(1)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(2)
+ArrayIteratorEx::next
+ArrayIteratorEx::valid
+ArrayIteratorEx::rewind
+ArrayIteratorEx::valid
+ArrayIteratorEx::current
+ArrayIteratorEx::key
+int(0)
+===DONE===
diff --git a/ext/spl/tests/iterator_009.phpt b/ext/spl/tests/iterator_009.phpt
new file mode 100644
index 0000000..0bfe74e
--- /dev/null
+++ b/ext/spl/tests/iterator_009.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: EmptyIterator
+--FILE--
+<?php
+
+class EmptyIteratorEx extends EmptyIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+}
+
+foreach (new EmptyIteratorEx() as $v) {
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+EmptyIteratorEx::rewind
+EmptyIteratorEx::valid
+===DONE===
diff --git a/ext/spl/tests/iterator_010.phpt b/ext/spl/tests/iterator_010.phpt
new file mode 100644
index 0000000..39d1000
--- /dev/null
+++ b/ext/spl/tests/iterator_010.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: EmptyIterator
+--FILE--
+<?php
+
+echo "===EmptyIterator===\n";
+
+foreach(new LimitIterator(new EmptyIterator(), 0, 3) as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0);
+--EXPECTF--
+===EmptyIterator===
+===DONE===
diff --git a/ext/spl/tests/iterator_011.phpt b/ext/spl/tests/iterator_011.phpt
new file mode 100644
index 0000000..fca159a
--- /dev/null
+++ b/ext/spl/tests/iterator_011.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: InfiniteIterator
+--FILE--
+<?php
+
+echo "===EmptyIterator===\n";
+
+foreach(new LimitIterator(new InfiniteIterator(new EmptyIterator()), 0, 3) as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===InfiniteIterator===\n";
+
+$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
+$it = new InfiniteIterator($it);
+$it = new LimitIterator($it, 2, 5);
+foreach($it as $val=>$key)
+{
+ echo "$val=>$key\n";
+}
+
+echo "===Infinite/LimitIterator===\n";
+
+$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
+$it = new LimitIterator($it, 1, 2);
+$it = new InfiniteIterator($it);
+$it = new LimitIterator($it, 2, 5);
+foreach($it as $val=>$key)
+{
+ echo "$val=>$key\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===EmptyIterator===
+===InfiniteIterator===
+2=>C
+3=>D
+0=>A
+1=>B
+2=>C
+===Infinite/LimitIterator===
+1=>B
+2=>C
+1=>B
+2=>C
+1=>B
+===DONE===
diff --git a/ext/spl/tests/iterator_012.phpt b/ext/spl/tests/iterator_012.phpt
new file mode 100644
index 0000000..81bc02f
--- /dev/null
+++ b/ext/spl/tests/iterator_012.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: NoRewindIterator
+--FILE--
+<?php
+
+echo "===Current===\n";
+
+$it = new NoRewindIterator(new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C')));
+
+echo $it->key() . '=>' . $it->current() . "\n";
+
+echo "===Next===\n";
+
+$it->next();
+
+echo "===Foreach===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===Current===
+0=>A
+===Next===
+===Foreach===
+1=>B
+2=>C
+===DONE===
diff --git a/ext/spl/tests/iterator_013.phpt b/ext/spl/tests/iterator_013.phpt
new file mode 100644
index 0000000..119631c
--- /dev/null
+++ b/ext/spl/tests/iterator_013.phpt
@@ -0,0 +1,66 @@
+--TEST--
+SPL: AppendIterator
+--FILE--
+<?php
+
+echo "===Empty===\n";
+
+$it = new AppendIterator;
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append(new ArrayIterator(array(0 => 'A', 1 => 'B')));
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Rewind===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append(new ArrayIterator(array(2 => 'C', 3 => 'D')));
+
+foreach(new NoRewindIterator($it) as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Rewind===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===Empty===
+===Append===
+0=>A
+1=>B
+===Rewind===
+0=>A
+1=>B
+===Append===
+2=>C
+3=>D
+===Rewind===
+0=>A
+1=>B
+2=>C
+3=>D
+===DONE===
diff --git a/ext/spl/tests/iterator_014.phpt b/ext/spl/tests/iterator_014.phpt
new file mode 100644
index 0000000..119fad0
--- /dev/null
+++ b/ext/spl/tests/iterator_014.phpt
@@ -0,0 +1,138 @@
+--TEST--
+SPL: RecursiveIteratorIterator and beginChildren/endChildren
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ function valid()
+ {
+ if (!parent::valid())
+ {
+ echo __METHOD__ . " = false\n";
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ function getChildren()
+ {
+ echo __METHOD__ . "\n";
+ return parent::getChildren();
+ }
+}
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+
+ function beginChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+
+ function endChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+}
+
+foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"))) as $k=>$v)
+{
+ echo "$k=>$v\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+RecursiveArrayIteratorIterator::rewind
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>a
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ba
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+1=>bbb
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(2)
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(3)
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bcaa
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(3)
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ca
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+3=>d
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::valid
+MyRecursiveArrayIterator::valid = false
+===DONE===
diff --git a/ext/spl/tests/iterator_015.phpt b/ext/spl/tests/iterator_015.phpt
new file mode 100644
index 0000000..aa30f79
--- /dev/null
+++ b/ext/spl/tests/iterator_015.phpt
@@ -0,0 +1,62 @@
+--TEST--
+SPL: RecursiveIteratorIterator and beginChildren/endChildren
+--FILE--
+<?php
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ function rewind()
+ {
+ echo "<ul>\n";
+ parent::rewind();
+ }
+ function beginChildren()
+ {
+ echo str_repeat(' ',$this->getDepth())."<ul>\n";
+ }
+
+ function endChildren()
+ {
+ echo str_repeat(' ',$this->getDepth())."</ul>\n";
+ }
+ function valid()
+ {
+ if (!parent::valid()) {
+ echo "<ul>\n";
+ return false;
+ }
+ return true;
+ }
+}
+
+$arr = array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d");
+$obj = new RecursiveArrayIterator($arr);
+$rit = new RecursiveArrayIteratorIterator($obj);
+foreach($rit as $k=>$v)
+{
+ echo str_repeat(' ',$rit->getDepth()+1)."$k=>$v\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+<ul>
+ 0=>a
+ <ul>
+ 0=>ba
+ <ul>
+ 0=>bba
+ 1=>bbb
+ </ul>
+ <ul>
+ <ul>
+ 0=>bcaa
+ </ul>
+ </ul>
+ </ul>
+ <ul>
+ 0=>ca
+ </ul>
+ 3=>d
+<ul>
+===DONE===
diff --git a/ext/spl/tests/iterator_016.phpt b/ext/spl/tests/iterator_016.phpt
new file mode 100644
index 0000000..f231c6e
--- /dev/null
+++ b/ext/spl/tests/iterator_016.phpt
@@ -0,0 +1,76 @@
+--TEST--
+SPL: RecursiveIteratorIterator and beginChildren/endChildren
+--FILE--
+<?php
+
+class Menu extends ArrayObject
+{
+ function getIterator()
+ {
+ echo __METHOD__ . "\n";
+ return new RecursiveArrayIterator($this);
+ }
+}
+
+class MenuOutput extends RecursiveIteratorIterator
+{
+ function __construct(Menu $it)
+ {
+ parent::__construct($it);
+ }
+ function rewind()
+ {
+ echo "<ul>\n";
+ parent::rewind();
+ }
+ function beginChildren()
+ {
+ echo str_repeat(' ',$this->getDepth())."<ul>\n";
+ }
+
+ function endChildren()
+ {
+ echo str_repeat(' ',$this->getDepth())."</ul>\n";
+ }
+ function valid()
+ {
+ if (!parent::valid()) {
+ echo "<ul>\n";
+ return false;
+ }
+ return true;
+ }
+}
+
+$arr = array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d");
+$obj = new Menu($arr);
+$rit = new MenuOutput($obj);
+foreach($rit as $k=>$v)
+{
+ echo str_repeat(' ',$rit->getDepth()+1)."$k=>$v\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Menu::getIterator
+<ul>
+ 0=>a
+ <ul>
+ 0=>ba
+ <ul>
+ 0=>bba
+ 1=>bbb
+ </ul>
+ <ul>
+ <ul>
+ 0=>bcaa
+ </ul>
+ </ul>
+ </ul>
+ <ul>
+ 0=>ca
+ </ul>
+ 3=>d
+<ul>
+===DONE===
diff --git a/ext/spl/tests/iterator_017.phpt b/ext/spl/tests/iterator_017.phpt
new file mode 100644
index 0000000..39d1000
--- /dev/null
+++ b/ext/spl/tests/iterator_017.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: EmptyIterator
+--FILE--
+<?php
+
+echo "===EmptyIterator===\n";
+
+foreach(new LimitIterator(new EmptyIterator(), 0, 3) as $key => $val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0);
+--EXPECTF--
+===EmptyIterator===
+===DONE===
diff --git a/ext/spl/tests/iterator_018.phpt b/ext/spl/tests/iterator_018.phpt
new file mode 100644
index 0000000..9c234bb
--- /dev/null
+++ b/ext/spl/tests/iterator_018.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: InfiniteIterator
+--FILE--
+<?php
+
+echo "===EmptyIterator===\n";
+
+foreach(new LimitIterator(new InfiniteIterator(new EmptyIterator()), 0, 3) as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===InfiniteIterator===\n";
+
+$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
+$it = new InfiniteIterator($it);
+$it = new LimitIterator($it, 2, 5);
+foreach($it as $val=>$key)
+{
+ echo "$val=>$key\n";
+}
+
+echo "===Infinite/LimitIterator===\n";
+
+$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'));
+$it = new LimitIterator($it, 1, 2);
+$it = new InfiniteIterator($it);
+$it = new LimitIterator($it, 2, 5);
+foreach($it as $val=>$key)
+{
+ echo "$val=>$key\n";
+}
+
+?>
+===DONE===
+<?php exit(0);
+--EXPECTF--
+===EmptyIterator===
+===InfiniteIterator===
+2=>C
+3=>D
+0=>A
+1=>B
+2=>C
+===Infinite/LimitIterator===
+1=>B
+2=>C
+1=>B
+2=>C
+1=>B
+===DONE===
diff --git a/ext/spl/tests/iterator_019.phpt b/ext/spl/tests/iterator_019.phpt
new file mode 100644
index 0000000..81bc02f
--- /dev/null
+++ b/ext/spl/tests/iterator_019.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: NoRewindIterator
+--FILE--
+<?php
+
+echo "===Current===\n";
+
+$it = new NoRewindIterator(new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C')));
+
+echo $it->key() . '=>' . $it->current() . "\n";
+
+echo "===Next===\n";
+
+$it->next();
+
+echo "===Foreach===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===Current===
+0=>A
+===Next===
+===Foreach===
+1=>B
+2=>C
+===DONE===
diff --git a/ext/spl/tests/iterator_020.phpt b/ext/spl/tests/iterator_020.phpt
new file mode 100644
index 0000000..119631c
--- /dev/null
+++ b/ext/spl/tests/iterator_020.phpt
@@ -0,0 +1,66 @@
+--TEST--
+SPL: AppendIterator
+--FILE--
+<?php
+
+echo "===Empty===\n";
+
+$it = new AppendIterator;
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append(new ArrayIterator(array(0 => 'A', 1 => 'B')));
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Rewind===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Append===\n";
+
+$it->append(new ArrayIterator(array(2 => 'C', 3 => 'D')));
+
+foreach(new NoRewindIterator($it) as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+echo "===Rewind===\n";
+
+foreach($it as $key=>$val)
+{
+ echo "$key=>$val\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===Empty===
+===Append===
+0=>A
+1=>B
+===Rewind===
+0=>A
+1=>B
+===Append===
+2=>C
+3=>D
+===Rewind===
+0=>A
+1=>B
+2=>C
+3=>D
+===DONE===
diff --git a/ext/spl/tests/iterator_021.phpt b/ext/spl/tests/iterator_021.phpt
new file mode 100644
index 0000000..4f2395a
--- /dev/null
+++ b/ext/spl/tests/iterator_021.phpt
@@ -0,0 +1,180 @@
+--TEST--
+SPL: RecursiveIteratorIterator and hasChildren
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ function valid()
+ {
+ if (!parent::valid())
+ {
+ echo __METHOD__ . " = false\n";
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ function getChildren()
+ {
+ echo __METHOD__ . "\n";
+ return parent::getChildren();
+ }
+}
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ private $max_depth;
+ private $over = 0;
+ private $skip = false;
+
+ function __construct($it, $max_depth)
+ {
+ $this->max_depth = $max_depth;
+ parent::__construct($it);
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->skip = false;
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ if ($this->skip)
+ {
+ $this->skip = false;
+ $this->next();
+ }
+ return parent::valid();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+
+ function callHasChildren()
+ {
+ $this->skip = false;
+ $has = parent::callHasChildren();
+ $res = $this->getDepth() < $this->max_depth && $has;
+ echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n";
+ if ($has && !$res)
+ {
+ $this->over++;
+ if ($this->over == 2) {
+ $this->skip = true;
+ }
+ }
+ return $res;
+ }
+
+ function beginChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+
+ function endChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+}
+
+foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v)
+{
+ if (is_array($v)) $v = join('',$v);
+ echo "$k=>$v\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+RecursiveArrayIteratorIterator::rewind
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>a
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(1) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+1=>bbb
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bcaa
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+MyRecursiveArrayIterator::getChildren
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(1) = no/no
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ca
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+3=>d
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::valid
+MyRecursiveArrayIterator::valid = false
+===DONE===
diff --git a/ext/spl/tests/iterator_022.phpt b/ext/spl/tests/iterator_022.phpt
new file mode 100644
index 0000000..8d05531
--- /dev/null
+++ b/ext/spl/tests/iterator_022.phpt
@@ -0,0 +1,186 @@
+--TEST--
+SPL: RecursiveIteratorIterator and callHasChildren/callGetChildren
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ function getChildren()
+ {
+ echo __METHOD__ . "\n";
+ return $this->current();
+ }
+
+ function valid()
+ {
+ if (!parent::valid())
+ {
+ echo __METHOD__ . " = false\n";
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+}
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ private $max_depth;
+ private $over = 0;
+ private $skip = false;
+
+ function __construct($it, $max_depth)
+ {
+ $this->max_depth = $max_depth;
+ parent::__construct($it);
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->skip = false;
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ if ($this->skip)
+ {
+ $this->skip = false;
+ $this->next();
+ }
+ return parent::valid();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+
+ function callHasChildren()
+ {
+ $this->skip = false;
+ $has = parent::callHasChildren();
+ $res = $this->getDepth() < $this->max_depth && $has;
+ echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n";
+ if ($has && !$res)
+ {
+ $this->over++;
+ if ($this->over == 2) {
+ $this->skip = true;
+ }
+ }
+ return $res;
+ }
+
+ function callGetChildren()
+ {
+ if ($this->over == 2)
+ {
+ echo __METHOD__ . "(skip)\n";
+ return NULL;
+ }
+ echo __METHOD__ . "(ok:{$this->over})\n";
+ return new MyRecursiveArrayIterator($this->current());
+ }
+
+ function beginChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+
+ function endChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+}
+
+try
+{
+ foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v)
+ {
+ if (is_array($v)) $v = join('',$v);
+ echo "$k=>$v\n";
+ }
+}
+catch(UnexpectedValueException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+RecursiveArrayIteratorIterator::rewind
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>a
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(1) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+1=>bbb
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bcaa
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(skip)
+Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator
+===DONE===
diff --git a/ext/spl/tests/iterator_023.phpt b/ext/spl/tests/iterator_023.phpt
new file mode 100644
index 0000000..1b6b468
--- /dev/null
+++ b/ext/spl/tests/iterator_023.phpt
@@ -0,0 +1,193 @@
+--TEST--
+SPL: RecursiveIteratorIterator and catch getChildren
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ function getChildren()
+ {
+ echo __METHOD__ . "\n";
+ return $this->current();
+ }
+
+ function valid()
+ {
+ if (!parent::valid())
+ {
+ echo __METHOD__ . " = false\n";
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+}
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ private $max_depth;
+ private $over = 0;
+ private $skip = false;
+
+ function __construct($it, $max_depth)
+ {
+ $this->max_depth = $max_depth;
+ parent::__construct($it, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->skip = false;
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ if ($this->skip)
+ {
+ $this->skip = false;
+ $this->next();
+ }
+ return parent::valid();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+
+ function callHasChildren()
+ {
+ $this->skip = false;
+ $has = parent::callHasChildren();
+ $res = $this->getDepth() < $this->max_depth && $has;
+ echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n";
+ if ($has && !$res)
+ {
+ $this->over++;
+ if ($this->over == 2) {
+ $this->skip = true;
+ }
+ }
+ return $res;
+ }
+
+ function callGetChildren()
+ {
+ if ($this->over == 2)
+ {
+ echo __METHOD__ . "(throw)\n";
+ throw new Exception("Thrown in callGetChildren()");
+ }
+ echo __METHOD__ . "(ok:{$this->over})\n";
+ return new MyRecursiveArrayIterator($this->current());
+ }
+
+ function beginChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+
+ function endChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ }
+}
+
+try
+{
+ foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v)
+ {
+ if (is_array($v)) $v = join('',$v);
+ echo "$k=>$v\n";
+ }
+}
+catch(UnexpectedValueException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+RecursiveArrayIteratorIterator::rewind
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>a
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(1) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>ba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bba
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+1=>bbb
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(ok:0)
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+0=>bcaa
+RecursiveArrayIteratorIterator::next
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(2)
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+RecursiveArrayIteratorIterator::callGetChildren(throw)
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::current
+RecursiveArrayIteratorIterator::key
+3=>d
+RecursiveArrayIteratorIterator::next
+MyRecursiveArrayIterator::valid = false
+RecursiveArrayIteratorIterator::valid
+MyRecursiveArrayIterator::valid = false
+===DONE===
diff --git a/ext/spl/tests/iterator_024.phpt b/ext/spl/tests/iterator_024.phpt
new file mode 100644
index 0000000..0c7dea1
--- /dev/null
+++ b/ext/spl/tests/iterator_024.phpt
@@ -0,0 +1,49 @@
+--TEST--
+SPL: RecursiveIteratorIterator with custom iterator class
+--FILE--
+<?php
+
+$ar = array(1, 2, array(31, 32, array(331)), 4);
+
+foreach(new RecursiveIteratorIterator(new ArrayObject($ar, 0, "RecursiveArrayIterator")) as $v) echo "$v\n";
+
+$it = new ArrayObject($ar);
+var_dump($it->getIteratorClass());
+
+try
+{
+ foreach(new RecursiveIteratorIterator(new ArrayObject($ar)) as $v) echo "$v\n";
+}
+catch (InvalidArgumentException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+echo "===MANUAL===\n";
+
+$it->setIteratorClass("RecursiveArrayIterator");
+var_dump($it->getIteratorClass());
+foreach(new RecursiveIteratorIterator($it) as $v) echo "$v\n";
+
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1
+2
+31
+32
+331
+4
+string(13) "ArrayIterator"
+An instance of RecursiveIterator or IteratorAggregate creating it is required
+===MANUAL===
+string(22) "RecursiveArrayIterator"
+1
+2
+31
+32
+331
+4
+===DONE===
diff --git a/ext/spl/tests/iterator_025.phpt b/ext/spl/tests/iterator_025.phpt
new file mode 100644
index 0000000..e582b1f
--- /dev/null
+++ b/ext/spl/tests/iterator_025.phpt
@@ -0,0 +1,92 @@
+--TEST--
+SPL: RecursiveIteratorIterator and begin/endIteration()
+--FILE--
+<?php
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator
+{
+ function beginIteration()
+ {
+ echo __METHOD__ . "()\n";
+ }
+
+ function endIteration()
+ {
+ echo __METHOD__ . "()\n";
+ }
+}
+
+$ar = array(1, 2, array(31, 32, array(331)), 4);
+
+$it = new MyRecursiveIteratorIterator(new ArrayObject($ar, 0, "RecursiveArrayIterator"));
+
+foreach($it as $v) echo "$v\n";
+
+echo "===MORE===\n";
+
+foreach($it as $v) echo "$v\n";
+
+echo "===MORE===\n";
+
+$it->rewind();
+foreach($it as $v) echo "$v\n";
+var_dump($it->valid());
+
+echo "===MANUAL===\n";
+
+$it->rewind();
+while($it->valid())
+{
+ echo $it->current() . "\n";
+ $it->next();
+ break;
+}
+$it->rewind();
+while($it->valid())
+{
+ echo $it->current() . "\n";
+ $it->next();
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+MyRecursiveIteratorIterator::beginIteration()
+1
+2
+31
+32
+331
+4
+MyRecursiveIteratorIterator::endIteration()
+===MORE===
+MyRecursiveIteratorIterator::beginIteration()
+1
+2
+31
+32
+331
+4
+MyRecursiveIteratorIterator::endIteration()
+===MORE===
+MyRecursiveIteratorIterator::beginIteration()
+1
+2
+31
+32
+331
+4
+MyRecursiveIteratorIterator::endIteration()
+bool(false)
+===MANUAL===
+MyRecursiveIteratorIterator::beginIteration()
+1
+1
+2
+31
+32
+331
+4
+MyRecursiveIteratorIterator::endIteration()
+===DONE===
diff --git a/ext/spl/tests/iterator_026.phpt b/ext/spl/tests/iterator_026.phpt
new file mode 100644
index 0000000..8eb77a7
--- /dev/null
+++ b/ext/spl/tests/iterator_026.phpt
@@ -0,0 +1,38 @@
+--TEST--
+SPL: CachingIterator::hasNext()
+--FILE--
+<?php
+
+$ar = array(1, 2, array(31, 32, array(331)), 4);
+
+$it = new RecursiveArrayIterator($ar);
+$it = new RecursiveCachingIterator($it);
+$it = new RecursiveIteratorIterator($it);
+
+foreach($it as $k=>$v)
+{
+ echo "$k=>$v\n";
+ echo "hasNext: " . ($it->getInnerIterator()->hasNext() ? "yes" : "no") . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+0=>1
+hasNext: yes
+1=>2
+hasNext: yes
+
+Notice: Array to string conversion in %siterator_026.php on line %d
+0=>31
+hasNext: yes
+1=>32
+hasNext: yes
+
+Notice: Array to string conversion in %siterator_026.php on line %d
+0=>331
+hasNext: no
+3=>4
+hasNext: no
+===DONE===
diff --git a/ext/spl/tests/iterator_027.phpt b/ext/spl/tests/iterator_027.phpt
new file mode 100644
index 0000000..fd9ba70
--- /dev/null
+++ b/ext/spl/tests/iterator_027.phpt
@@ -0,0 +1,83 @@
+--TEST--
+SPL: CachingIterator::FULL_CACHE
+--FILE--
+<?php
+
+$ar = array(1, 2, array(31, 32, array(331)), 4);
+
+$it = new RecursiveArrayIterator($ar);
+$it = new RecursiveIteratorIterator($it);
+$it = new CachingIterator($it, CachingIterator::FULL_CACHE);
+
+foreach($it as $k=>$v)
+{
+ echo "$k=>$v\n";
+}
+
+echo "===CHECK===\n";
+
+for ($i = 0; $i < 4; $i++)
+{
+ if (isset($it[$i]))
+ {
+ var_dump($i, $it[$i]);
+ }
+}
+
+$it[2] = 'foo';
+$it[3] = 'bar';
+$it['baz'] = '25';
+
+var_dump($it[2]);
+var_dump($it[3]);
+var_dump($it['baz']);
+
+unset($it[0]);
+unset($it[2]);
+unset($it['baz']);
+
+var_dump(isset($it[0])); // unset
+var_dump(isset($it[1])); // still present
+var_dump(isset($it[2])); // unset
+var_dump(isset($it[3])); // still present
+var_dump(isset($it['baz']));
+
+echo "===REWIND===\n";
+
+$it->rewind(); // cleans and reads first element
+var_dump(isset($it[0])); // pre-fetched
+var_dump(isset($it[1])); // deleted
+var_dump(isset($it[2])); // unset
+var_dump(isset($it[3])); // deleted
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+0=>1
+1=>2
+0=>31
+1=>32
+0=>331
+3=>4
+===CHECK===
+int(0)
+int(331)
+int(1)
+int(32)
+int(3)
+int(4)
+string(3) "foo"
+string(3) "bar"
+string(2) "25"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+===REWIND===
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/iterator_028.phpt b/ext/spl/tests/iterator_028.phpt
new file mode 100644
index 0000000..8b53b21
--- /dev/null
+++ b/ext/spl/tests/iterator_028.phpt
@@ -0,0 +1,112 @@
+--TEST--
+SPL: RecursiveIteratorIterator and setMaxDepth()
+--FILE--
+<?php
+
+$ar = array(1, 2, array(31, 32, array(331, array(3321, array(33221)))), 4);
+
+$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($ar));
+
+echo "===?===\n";
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===2===\n";
+$it->setMaxDepth(2);
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===X===\n";
+$it->setMaxDepth();
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===3===\n";
+$it->setMaxDepth(3);
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===5===\n";
+$it->setMaxDepth(5);
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===0===\n";
+$it->setMaxDepth(0);
+var_dump($it->getMaxDepth());
+foreach($it as $v) echo $it->getDepth() . ": $v\n";
+
+echo "===-1===\n";
+$it->setMaxDepth(-1);
+var_dump($it->getMaxDepth());
+try
+{
+ $it->setMaxDepth(4);
+ $it->setMaxDepth(-2);
+}
+catch(Exception $e)
+{
+ var_dump($e->getMessage());
+}
+var_dump($it->getMaxDepth());
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===?===
+bool(false)
+0: 1
+0: 2
+1: 31
+1: 32
+2: 331
+3: 3321
+4: 33221
+0: 4
+===2===
+int(2)
+0: 1
+0: 2
+1: 31
+1: 32
+2: 331
+0: 4
+===X===
+bool(false)
+0: 1
+0: 2
+1: 31
+1: 32
+2: 331
+3: 3321
+4: 33221
+0: 4
+===3===
+int(3)
+0: 1
+0: 2
+1: 31
+1: 32
+2: 331
+3: 3321
+0: 4
+===5===
+int(5)
+0: 1
+0: 2
+1: 31
+1: 32
+2: 331
+3: 3321
+4: 33221
+0: 4
+===0===
+int(0)
+0: 1
+0: 2
+0: 4
+===-1===
+bool(false)
+string(33) "Parameter max_depth must be >= -1"
+int(4)
+===DONE===
diff --git a/ext/spl/tests/iterator_029.phpt b/ext/spl/tests/iterator_029.phpt
new file mode 100644
index 0000000..e5bfde0
--- /dev/null
+++ b/ext/spl/tests/iterator_029.phpt
@@ -0,0 +1,38 @@
+--TEST--
+SPL: RegexIterator
+--FILE--
+<?php
+
+$ar = array(0, "123", 123, 22 => "abc", "a2b", 22, "a2d" => 7, 42);
+
+foreach(new RegexIterator(new ArrayIterator($ar), "/2/") as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===KEY===
+<?php
+
+foreach(new RegexIterator(new ArrayIterator($ar), "/2/", 0, RegexIterator::USE_KEY) as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1=>123
+2=>123
+23=>a2b
+24=>22
+25=>42
+===KEY===
+2=>123
+22=>abc
+23=>a2b
+24=>22
+a2d=>7
+25=>42
+===DONE===
diff --git a/ext/spl/tests/iterator_030.phpt b/ext/spl/tests/iterator_030.phpt
new file mode 100644
index 0000000..29d147f
--- /dev/null
+++ b/ext/spl/tests/iterator_030.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: EmptyIterator access
+--FILE--
+<?php
+
+$it = new EmptyIterator;
+
+var_dump($it->valid());
+$it->rewind();
+var_dump($it->valid());
+$it->next();
+var_dump($it->valid());
+
+try
+{
+ var_dump($it->key());
+}
+catch(BadMethodCallException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+try
+{
+ var_dump($it->current());
+}
+catch(BadMethodCallException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+var_dump($it->valid());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(false)
+Accessing the key of an EmptyIterator
+Accessing the value of an EmptyIterator
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt
new file mode 100644
index 0000000..40342f4
--- /dev/null
+++ b/ext/spl/tests/iterator_031.phpt
@@ -0,0 +1,116 @@
+--TEST--
+SPL: AppendIterator::append() rewinds when neccessary
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+}
+
+$it = new MyArrayIterator(array(1,2));
+
+foreach($it as $k=>$v)
+{
+ echo "$k=>$v\n";
+}
+
+class MyAppendIterator extends AppendIterator
+{
+ function __construct()
+ {
+ echo __METHOD__ . "\n";
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+
+ function append(Iterator $what)
+ {
+ echo __METHOD__ . "\n";
+ parent::append($what);
+ }
+
+ function parent__construct()
+ {
+ parent::__construct();
+ }
+}
+
+$ap = new MyAppendIterator;
+
+try
+{
+ $ap->append($it);
+}
+catch(LogicException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+$ap->parent__construct();
+
+try
+{
+ $ap->parent__construct($it);
+}
+catch(BadMethodCallException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+$ap->append($it);
+$ap->append($it);
+$ap->append($it);
+
+foreach($ap as $k=>$v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+MyArrayIterator::rewind
+0=>1
+1=>2
+MyAppendIterator::__construct
+MyAppendIterator::append
+The object is in an invalid state as the parent constructor was not called
+AppendIterator::getIterator() must be called exactly once per instance
+MyAppendIterator::append
+MyArrayIterator::rewind
+MyAppendIterator::append
+MyAppendIterator::append
+MyAppendIterator::rewind
+MyArrayIterator::rewind
+MyAppendIterator::valid
+0=>1
+MyAppendIterator::valid
+1=>2
+MyArrayIterator::rewind
+MyAppendIterator::valid
+0=>1
+MyAppendIterator::valid
+1=>2
+MyArrayIterator::rewind
+MyAppendIterator::valid
+0=>1
+MyAppendIterator::valid
+1=>2
+MyAppendIterator::valid
+===DONE===
diff --git a/ext/spl/tests/iterator_032.phpt b/ext/spl/tests/iterator_032.phpt
new file mode 100644
index 0000000..84eb8e6
--- /dev/null
+++ b/ext/spl/tests/iterator_032.phpt
@@ -0,0 +1,50 @@
+--TEST--
+SPL: LimitIterator::getPosition()
+--FILE--
+<?php
+
+$it = new LimitIterator(new ArrayIterator(array(1,2,3,4)), 1, 2);
+
+foreach($it as $k=>$v)
+{
+ echo "$k=>$v\n";
+ var_dump($it->getPosition());
+}
+
+try
+{
+ $it->seek(0);
+}
+catch(OutOfBoundsException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+$it->seek(2);
+var_dump($it->current());
+
+try
+{
+ $it->seek(3);
+}
+catch(OutOfBoundsException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+$it->next();
+var_dump($it->valid());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1=>2
+int(1)
+2=>3
+int(2)
+Cannot seek to 0 which is below the offset 1
+int(3)
+Cannot seek to 3 which is behind offset 1 plus count 2
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/iterator_033.phpt b/ext/spl/tests/iterator_033.phpt
new file mode 100644
index 0000000..548759c
--- /dev/null
+++ b/ext/spl/tests/iterator_033.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: ParentIterator
+--FILE--
+<?php
+
+$it = new ParentIterator(new RecursiveArrayIterator(array(1,array(21,22, array(231)),3)));
+
+foreach(new RecursiveIteratorIterator($it) as $k=>$v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+echo "==SECOND==\n";
+
+foreach(new RecursiveIteratorIterator($it, 1) as $k=>$v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+==SECOND==
+int(1)
+array(3) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+ [2]=>
+ array(1) {
+ [0]=>
+ int(231)
+ }
+}
+int(2)
+array(1) {
+ [0]=>
+ int(231)
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_034.phpt b/ext/spl/tests/iterator_034.phpt
new file mode 100644
index 0000000..3329e74
--- /dev/null
+++ b/ext/spl/tests/iterator_034.phpt
@@ -0,0 +1,188 @@
+--TEST--
+SPL: RecursiveIteratorIterator and break deep
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ function valid()
+ {
+ if (!parent::valid())
+ {
+ echo __METHOD__ . "() = false\n";
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ function getChildren()
+ {
+ echo __METHOD__ . "()\n";
+ return parent::getChildren();
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "()\n";
+ parent::rewind();
+ }
+}
+
+class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator
+{
+ private $max_depth;
+ private $over = 0;
+
+ function __construct($it, $max_depth)
+ {
+ $this->max_depth = $max_depth;
+ parent::__construct($it);
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "() - BEGIN\n";
+ parent::rewind();
+ echo __METHOD__ . "() - DONE\n";
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "()\n";
+ return parent::valid();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "()\n";
+ return parent::current();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "()\n";
+ return parent::key();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "()\n";
+ parent::next();
+ }
+
+ function callHasChildren()
+ {
+ $has = parent::callHasChildren();
+ $res = $this->getDepth() < $this->max_depth && $has;
+ echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n";
+ return $res;
+ }
+
+ function beginChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ parent::beginChildren();
+ }
+
+ function endChildren()
+ {
+ echo __METHOD__ . "(".$this->getDepth().")\n";
+ parent::endChildren();
+ }
+}
+
+$p = 0;
+$it = new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2);
+foreach($it as $k=>$v)
+{
+ if (is_array($v)) $v = join('',$v);
+ echo "$k=>$v\n";
+ if ($p++ == 5)
+ {
+ echo "===BREAK===\n";
+ break;
+ }
+}
+
+echo "===FOREND===\n";
+
+$it->rewind();
+
+echo "===CHECK===\n";
+
+var_dump($it->valid());
+var_dump($it->current() == "a");
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+RecursiveArrayIteratorIterator::rewind() - BEGIN
+MyRecursiveArrayIterator::rewind()
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::rewind() - DONE
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+0=>a
+RecursiveArrayIteratorIterator::next()
+RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::rewind()
+RecursiveArrayIteratorIterator::beginChildren(1)
+RecursiveArrayIteratorIterator::callHasChildren(1) = no/no
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+0=>ba
+RecursiveArrayIteratorIterator::next()
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::rewind()
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+0=>bba
+RecursiveArrayIteratorIterator::next()
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/no
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+1=>bbb
+RecursiveArrayIteratorIterator::next()
+MyRecursiveArrayIterator::valid() = false
+RecursiveArrayIteratorIterator::endChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::rewind()
+RecursiveArrayIteratorIterator::beginChildren(2)
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+0=>bcaa
+RecursiveArrayIteratorIterator::next()
+RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes
+RecursiveArrayIteratorIterator::valid()
+RecursiveArrayIteratorIterator::current()
+RecursiveArrayIteratorIterator::key()
+1=>bcba
+===BREAK===
+===FOREND===
+RecursiveArrayIteratorIterator::rewind() - BEGIN
+RecursiveArrayIteratorIterator::endChildren(1)
+RecursiveArrayIteratorIterator::endChildren(0)
+MyRecursiveArrayIterator::rewind()
+RecursiveArrayIteratorIterator::callHasChildren(0) = no/no
+RecursiveArrayIteratorIterator::rewind() - DONE
+===CHECK===
+RecursiveArrayIteratorIterator::valid()
+bool(true)
+RecursiveArrayIteratorIterator::current()
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt
new file mode 100644
index 0000000..9ce098b
--- /dev/null
+++ b/ext/spl/tests/iterator_035.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: ArrayIterator and values assigned by reference
+--FILE--
+<?php
+
+$tmp = 1;
+
+$a = new ArrayIterator();
+$a[] = $tmp;
+$a[] = &$tmp;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Cannot assign by reference to overloaded object in %s on line %d
diff --git a/ext/spl/tests/iterator_036.phpt b/ext/spl/tests/iterator_036.phpt
new file mode 100644
index 0000000..9a9e66b
--- /dev/null
+++ b/ext/spl/tests/iterator_036.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: CachingIterator and __toString and flags = 0
+--FILE--
+<?php
+
+function test($it)
+{
+ foreach($it as $v)
+ {
+ var_dump((string)$it);
+ }
+}
+
+$ar = new ArrayIterator(array(1, 2, 3));
+
+test(new CachingIterator($ar, 0));
+
+?>
+===DONE===
+--EXPECTF--
+
+Fatal error: Method CachingIterator::__toString() must not throw an exception in %siterator_036.php on line %d
diff --git a/ext/spl/tests/iterator_037.phpt b/ext/spl/tests/iterator_037.phpt
new file mode 100644
index 0000000..2aa61bb
--- /dev/null
+++ b/ext/spl/tests/iterator_037.phpt
@@ -0,0 +1,131 @@
+--TEST--
+SPL: CachingIterator and __toString
+--FILE--
+<?php
+
+function test($ar, $flags)
+{
+ echo "===$flags===\n";
+ $it = new CachingIterator($ar, 0);
+ try
+ {
+ $it->setFlags($flags);
+ }
+ catch (Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ var_dump($it->getFlags());
+ return;
+ }
+ var_dump($it->getFlags());
+ try
+ {
+ foreach($it as $v)
+ {
+ var_dump((string)$it);
+ }
+ }
+ catch (Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ }
+}
+
+class MyItem
+{
+ function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ function __toString()
+ {
+ return (string)$this->value;
+ }
+}
+
+class MyArrayIterator extends ArrayIterator
+{
+ function __toString()
+ {
+ return $this->key() . ':' . $this->current();
+ }
+}
+
+$ar = new MyArrayIterator(array(1, 2, 3));
+
+test($ar, CachingIterator::CALL_TOSTRING);
+test($ar, CachingIterator::TOSTRING_USE_KEY);
+test($ar, CachingIterator::TOSTRING_USE_CURRENT);
+
+$ar = new MyArrayIterator(array(new MyItem(1), new MyItem(2), new MyItem(3)));
+
+test($ar, CachingIterator::TOSTRING_USE_INNER);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_KEY);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_CURRENT);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_INNER);
+test($ar, CachingIterator::TOSTRING_USE_KEY | CachingIterator::TOSTRING_USE_CURRENT);
+test($ar, CachingIterator::TOSTRING_USE_KEY | CachingIterator::TOSTRING_USE_INNER);
+
+echo "===X===\n";
+try
+{
+ $it = new CachingIterator($ar, CachingIterator::CALL_TOSTRING);
+ $it->setFlags(0);
+}
+catch (Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+try
+{
+ $it = new CachingIterator($ar, CachingIterator::TOSTRING_USE_INNER);
+ $it->setFlags(0);
+}
+catch (Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+===1===
+int(1)
+string(1) "1"
+string(1) "2"
+string(1) "3"
+===2===
+int(2)
+string(1) "0"
+string(1) "1"
+string(1) "2"
+===4===
+int(4)
+string(1) "1"
+string(1) "2"
+string(1) "3"
+===8===
+int(8)
+string(3) "0:1"
+string(3) "1:2"
+string(3) "2:3"
+===3===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===5===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===9===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===6===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===10===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===X===
+Exception: Unsetting flag CALL_TO_STRING is not possible
+Exception: Unsetting flag TOSTRING_USE_INNER is not possible
+===DONE===
diff --git a/ext/spl/tests/iterator_038.phpt b/ext/spl/tests/iterator_038.phpt
new file mode 100644
index 0000000..9b890e2
--- /dev/null
+++ b/ext/spl/tests/iterator_038.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: RoRewindIterator and string keys
+--FILE--
+<?php
+
+foreach(new NoRewindIterator(new ArrayIterator(array('Hello'=>0, 'World'=>1))) as $k => $v)
+{
+ var_dump($v);
+ var_dump($k);
+}
+
+?>
+===DONE===
+--EXPECT--
+int(0)
+string(5) "Hello"
+int(1)
+string(5) "World"
+===DONE===
diff --git a/ext/spl/tests/iterator_039.phpt b/ext/spl/tests/iterator_039.phpt
new file mode 100644
index 0000000..17c9bc1
--- /dev/null
+++ b/ext/spl/tests/iterator_039.phpt
@@ -0,0 +1,121 @@
+--TEST--
+SPL: LimitIterator and backward seeking
+--FILE--
+<?php
+
+class NumericArrayIterator implements Iterator
+{
+ protected $a;
+ protected $i = 0;
+
+ public function __construct($a)
+ {
+ echo __METHOD__ . "\n";
+ $this->a = $a;
+ }
+
+ public function valid()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i < count($this->a);
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->i = 0;
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return $this->a[$this->i];
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->i++;
+ }
+}
+
+$it = new LimitIterator(new NumericArrayIterator(array(12, 25, 42, 56)));
+
+foreach($it as $k => $v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+echo "===SEEK===\n";
+
+$it->seek(2);
+
+echo "===LOOP===\n";
+
+foreach(new NoRewindIterator($it) as $k => $v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+NumericArrayIterator::valid
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(0)
+int(12)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(1)
+int(25)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(2)
+int(42)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(3)
+int(56)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+===SEEK===
+NumericArrayIterator::rewind
+NumericArrayIterator::valid
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+===LOOP===
+int(2)
+int(42)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(3)
+int(56)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+===DONE===
diff --git a/ext/spl/tests/iterator_040.phpt b/ext/spl/tests/iterator_040.phpt
new file mode 100644
index 0000000..ae00c81
--- /dev/null
+++ b/ext/spl/tests/iterator_040.phpt
@@ -0,0 +1,47 @@
+--TEST--
+SPL: RecursiveFilterIterator
+--FILE--
+<?php
+
+class MyRecursiveFilterIterator extends RecursiveFilterIterator
+{
+ function accept()
+ {
+ return true;
+ }
+}
+
+$ar = array(1, array(21, 22), 3);
+$it = new RecursiveArrayIterator($ar);
+$it = new MyRecursiveFilterIterator($it);
+$it = new RecursiveIteratorIterator($it);
+
+foreach($it as $k => $v)
+{
+ echo "===\n";
+ var_dump($it->getDepth());
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===
+int(0)
+int(0)
+int(1)
+===
+int(1)
+int(0)
+int(21)
+===
+int(1)
+int(1)
+int(22)
+===
+int(0)
+int(2)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/iterator_041.phpt b/ext/spl/tests/iterator_041.phpt
new file mode 100644
index 0000000..e00ac6b
--- /dev/null
+++ b/ext/spl/tests/iterator_041.phpt
@@ -0,0 +1,117 @@
+--TEST--
+SPL: iterator_to_array() and exceptions
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+// self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 0;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===iterator_to_array===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 4: current()
+State 5: key()
+State 6: next()
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
+===iterator_count===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 6: next()
+int(2)
+===DONE===
diff --git a/ext/spl/tests/iterator_041a.phpt b/ext/spl/tests/iterator_041a.phpt
new file mode 100644
index 0000000..ec999a5
--- /dev/null
+++ b/ext/spl/tests/iterator_041a.phpt
@@ -0,0 +1,107 @@
+--TEST--
+SPL: iterator_to_array() and exceptions from destruct
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+ self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 7;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===iterator_to_array===
+State 7: __destruct()
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
+===iterator_count===
+State 7: __destruct()
+int(2)
+===DONE===
diff --git a/ext/spl/tests/iterator_041b.phpt b/ext/spl/tests/iterator_041b.phpt
new file mode 100644
index 0000000..e7ea8b8
--- /dev/null
+++ b/ext/spl/tests/iterator_041b.phpt
@@ -0,0 +1,123 @@
+--TEST--
+SPL: iterator_to_array() and exceptions from delayed destruct
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+ self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 0;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ try {
+ $e = null;
+ } catch (Exception $e) {
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===iterator_to_array===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 4: current()
+State 5: key()
+State 6: next()
+State 7: __destruct()
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
+===iterator_count===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 6: next()
+State 7: __destruct()
+int(2)
+===DONE===
diff --git a/ext/spl/tests/iterator_042.phpt b/ext/spl/tests/iterator_042.phpt
new file mode 100644
index 0000000..95fea2f
--- /dev/null
+++ b/ext/spl/tests/iterator_042.phpt
@@ -0,0 +1,123 @@
+--TEST--
+SPL: AppendIterator and its ArrayIterator
+--FILE--
+<?php
+
+function test_error_handler($errno, $msg, $filename, $linenum, $vars)
+{
+ echo "Error $msg in $filename on line $linenum\n";
+ return true;
+}
+
+set_error_handler('test_error_handler');
+
+$it = new AppendIterator;
+
+$it->append(array());
+$it->append(new ArrayIterator(array(1)));
+$it->append(new ArrayIterator(array(21, 22)));
+
+var_dump($it->getArrayIterator());
+
+$it->append(new ArrayIterator(array(31, 32, 33)));
+
+var_dump($it->getArrayIterator());
+
+$idx = 0;
+
+foreach($it as $k => $v)
+{
+ echo '===' . $idx++ . "===\n";
+ var_dump($it->getIteratorIndex());
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Error Argument 1 passed to AppendIterator::append() must implement interface Iterator, array given in %siterator_042.php on line %d
+object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(2) {
+ [0]=>
+ object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(1) {
+ [0]=>
+ int(1)
+ }
+ }
+ [1]=>
+ object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+ }
+ }
+ }
+}
+object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(3) {
+ [0]=>
+ object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(1) {
+ [0]=>
+ int(1)
+ }
+ }
+ [1]=>
+ object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+ }
+ }
+ [2]=>
+ object(ArrayIterator)#5 (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(3) {
+ [0]=>
+ int(31)
+ [1]=>
+ int(32)
+ [2]=>
+ int(33)
+ }
+ }
+ }
+}
+===0===
+int(0)
+int(0)
+int(1)
+===1===
+int(1)
+int(0)
+int(21)
+===2===
+int(1)
+int(1)
+int(22)
+===3===
+int(2)
+int(0)
+int(31)
+===4===
+int(2)
+int(1)
+int(32)
+===5===
+int(2)
+int(2)
+int(33)
+===DONE===
diff --git a/ext/spl/tests/iterator_043.phpt b/ext/spl/tests/iterator_043.phpt
new file mode 100644
index 0000000..301a593
--- /dev/null
+++ b/ext/spl/tests/iterator_043.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: RecursiveCachingIterator and uninitialized getChildren()
+--FILE--
+<?php
+
+$it = new RecursiveCachingIterator(new RecursiveArrayIterator(array(1,2)));
+
+var_dump($it->getChildren());
+$it->rewind();
+var_dump($it->getChildren());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+NULL
+NULL
+===DONE===
diff --git a/ext/spl/tests/iterator_044.phpt b/ext/spl/tests/iterator_044.phpt
new file mode 100644
index 0000000..1271cca
--- /dev/null
+++ b/ext/spl/tests/iterator_044.phpt
@@ -0,0 +1,165 @@
+--TEST--
+SPL: CachingIterator and offsetGet/Exists using flag FULL_CACHE
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function test($ar)
+ {
+ foreach($ar as $k => $v)
+ {
+ echo "===$k===\n";
+ var_dump($v);
+ var_dump($this->offsetExists($v));
+ var_dump($this->offsetGet($v));
+ }
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)));
+
+try
+{
+ var_dump($it->offsetExists(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+try
+{
+ var_dump($it->offsetGet(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)), CachingIterator::FULL_CACHE);
+
+var_dump($it->offsetExists());
+var_dump($it->offsetGet());
+
+$checks = array(0, new stdClass, new MyFoo, NULL, 2, 'foo', 3);
+
+$it->test($checks);
+
+echo "===FILL===\n";
+
+foreach($it as $v); // read all into cache
+
+$it->test($checks);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+
+Warning: CachingIterator::offsetExists() expects exactly 1 parameter, 0 given in %siterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects exactly 1 parameter, 0 given in %siterator_044.php on line %d
+NULL
+===0===
+int(0)
+bool(false)
+
+Notice: Undefined index: 0 in %siterator_044.php on line %d
+NULL
+===1===
+object(stdClass)#%d (0) {
+}
+
+Warning: CachingIterator::offsetExists() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+===2===
+object(MyFoo)#%d (0) {
+}
+bool(false)
+
+Notice: Undefined index: foo in %siterator_044.php on line %d
+NULL
+===3===
+NULL
+bool(false)
+
+Notice: Undefined index: in %siterator_044.php on line %d
+NULL
+===4===
+int(2)
+bool(false)
+
+Notice: Undefined index: 2 in %siterator_044.php on line %d
+NULL
+===5===
+string(3) "foo"
+bool(false)
+
+Notice: Undefined index: foo in %siterator_044.php on line %d
+NULL
+===6===
+int(3)
+bool(false)
+
+Notice: Undefined index: 3 in %siterator_044.php on line %d
+NULL
+===FILL===
+===0===
+int(0)
+bool(true)
+int(0)
+===1===
+object(stdClass)#1 (0) {
+}
+
+Warning: CachingIterator::offsetExists() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+===2===
+object(MyFoo)#2 (0) {
+}
+bool(true)
+int(1)
+===3===
+NULL
+bool(false)
+
+Notice: Undefined index: in %siterator_044.php on line %d
+NULL
+===4===
+int(2)
+bool(true)
+int(4)
+===5===
+string(3) "foo"
+bool(true)
+int(1)
+===6===
+int(3)
+bool(false)
+
+Notice: Undefined index: 3 in %siterator_044.php on line %d
+NULL
+===DONE===
diff --git a/ext/spl/tests/iterator_045.phpt b/ext/spl/tests/iterator_045.phpt
new file mode 100644
index 0000000..d76b2d9
--- /dev/null
+++ b/ext/spl/tests/iterator_045.phpt
@@ -0,0 +1,169 @@
+--TEST--
+SPL: CachingIterator and offsetSet/Unset, getCache using flag FULL_CACHE
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function testSet($ar)
+ {
+ echo __METHOD__ . "()\n";
+ foreach($ar as $k => $v)
+ {
+ echo "set($k,$v)\n";
+ $this->offsetSet($k, $v);
+ }
+ }
+
+ function testUnset($ar)
+ {
+ echo __METHOD__ . "()\n";
+ foreach($ar as $k => $v)
+ {
+ echo "unset($v)\n";
+ $this->offsetUnset($v);
+ }
+ }
+
+ function fill()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v) ;
+ }
+
+ function show()
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($this->getCache());
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)));
+
+try
+{
+ var_dump($it->offsetSet(0, 0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+try
+{
+ var_dump($it->offsetUnset(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 1, 2, 3)), CachingIterator::FULL_CACHE);
+
+var_dump($it->offsetSet());
+var_dump($it->offsetSet(0));
+var_dump($it->offsetUnset());
+
+$checks = array(0 => 25, 1 => 42, 3 => 'FooBar');
+$unsets = array(0, 2);
+
+$it->testSet($checks);
+$it->show();
+$it->testUnset($unsets);
+$it->show();
+$it->fill();
+$it->show();
+$it->testSet($checks);
+$it->show();
+$it->testUnset($unsets);
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+
+Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 0 given in %siterator_045.php on line %d
+NULL
+
+Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 1 given in %siterator_045.php on line %d
+NULL
+
+Warning: CachingIterator::offsetUnset() expects exactly 1 parameter, 0 given in %siterator_045.php on line %d
+NULL
+MyCachingIterator::testSet()
+set(0,25)
+set(1,42)
+set(3,FooBar)
+MyCachingIterator::show()
+array(3) {
+ [0]=>
+ int(25)
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::testUnset()
+unset(0)
+unset(2)
+MyCachingIterator::show()
+array(2) {
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::fill()
+MyCachingIterator::show()
+array(4) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+}
+MyCachingIterator::testSet()
+set(0,25)
+set(1,42)
+set(3,FooBar)
+MyCachingIterator::show()
+array(4) {
+ [0]=>
+ int(25)
+ [1]=>
+ int(42)
+ [2]=>
+ int(2)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::testUnset()
+unset(0)
+unset(2)
+MyCachingIterator::show()
+array(2) {
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_046.phpt b/ext/spl/tests/iterator_046.phpt
new file mode 100644
index 0000000..f57415a
--- /dev/null
+++ b/ext/spl/tests/iterator_046.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: CachingIterator and __toString using bypassed string keys
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function fill()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v) ;
+ }
+
+ function show()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v)
+ {
+ var_dump((string)$this);
+ }
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 'bar'=>2)), CachingIterator::TOSTRING_USE_KEY);
+
+$it->fill();
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+MyCachingIterator::fill()
+MyCachingIterator::show()
+string(1) "0"
+string(3) "foo"
+string(3) "bar"
+===DONE===
diff --git a/ext/spl/tests/iterator_047.phpt b/ext/spl/tests/iterator_047.phpt
new file mode 100644
index 0000000..548f486
--- /dev/null
+++ b/ext/spl/tests/iterator_047.phpt
@@ -0,0 +1,125 @@
+--TEST--
+SPL: RecursiveCachingIterator and exception in has/getChildren
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ static public $fail = 0;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function hasChildren()
+ {
+ echo __METHOD__ . "()\n";
+ self::fail(1, __METHOD__);
+ return parent::hasChildren();
+ }
+
+ function getChildren()
+ {
+ echo __METHOD__ . "()\n";
+ self::fail(2, __METHOD__);
+ return parent::getChildren();
+ }
+}
+
+class MyRecursiveCachingIterator extends RecursiveCachingIterator
+{
+ function show()
+ {
+ MyRecursiveArrayIterator::$fail = 0;
+ while(MyRecursiveArrayIterator::$fail < 4)
+ {
+ echo "===" . MyRecursiveArrayIterator::$fail . "===\n";
+ try
+ {
+ foreach(new RecursiveIteratorIterator($this) as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+ catch (Exception $e)
+ {
+ echo "Exception: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine() . "\n";
+ }
+ MyRecursiveArrayIterator::$fail++;
+ }
+ }
+}
+
+$it = new MyRecursiveArrayIterator(array(0, array(10), 2, array(30), 4));
+$it = new MyRecursiveCachingIterator($it);
+
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===0===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+
+Notice: Array to string conversion in %siterator_047.php on line %d
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(10)
+MyRecursiveArrayIterator::hasChildren()
+int(2)
+int(2)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+
+Notice: Array to string conversion in %siterator_047.php on line %d
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(30)
+MyRecursiveArrayIterator::hasChildren()
+int(4)
+int(4)
+===1===
+MyRecursiveArrayIterator::hasChildren()
+Exception: State 1: MyRecursiveArrayIterator::hasChildren() in %s on line %d
+===2===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+Exception: State 2: MyRecursiveArrayIterator::getChildren() in %s on line %d
+===3===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+
+Notice: Array to string conversion in %siterator_047.php on line %d
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(10)
+MyRecursiveArrayIterator::hasChildren()
+int(2)
+int(2)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+
+Notice: Array to string conversion in %siterator_047.php on line %d
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(30)
+MyRecursiveArrayIterator::hasChildren()
+int(4)
+int(4)
+===DONE===
diff --git a/ext/spl/tests/iterator_048.phpt b/ext/spl/tests/iterator_048.phpt
new file mode 100644
index 0000000..bad4e78
--- /dev/null
+++ b/ext/spl/tests/iterator_048.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: RecursiveRegexIterator and exception in has/getChildren
+--FILE--
+<?php
+
+class MyRecursiveRegexIterator extends RecursiveRegexIterator
+{
+ function show()
+ {
+ foreach(new RecursiveIteratorIterator($this) as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ return $this->hasChildren() || parent::accept();
+ }
+}
+
+$ar = new RecursiveArrayIterator(array('Foo', array('Bar'), 'FooBar', array('Baz'), 'Biz'));
+$it = new MyRecursiveRegexIterator($ar, '/Bar/');
+
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(0)
+string(3) "Bar"
+int(2)
+string(6) "FooBar"
+===DONE===
diff --git a/ext/spl/tests/iterator_049.phpt b/ext/spl/tests/iterator_049.phpt
new file mode 100644
index 0000000..b9ab2c3
--- /dev/null
+++ b/ext/spl/tests/iterator_049.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: ArrayIterator with NULL key
+--FILE--
+<?php
+
+$ar = new ArrayIterator(array(NULL=>NULL));
+@var_dump($ar);
+var_dump($ar->getArrayCopy());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(1) {
+ [""]=>
+ NULL
+ }
+}
+array(1) {
+ [""]=>
+ NULL
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_049b.phpt b/ext/spl/tests/iterator_049b.phpt
new file mode 100644
index 0000000..03c7350
--- /dev/null
+++ b/ext/spl/tests/iterator_049b.phpt
Binary files differ
diff --git a/ext/spl/tests/iterator_050.phpt b/ext/spl/tests/iterator_050.phpt
new file mode 100644
index 0000000..fed4a3b
--- /dev/null
+++ b/ext/spl/tests/iterator_050.phpt
@@ -0,0 +1,98 @@
+--TEST--
+SPL: RegexIterator::GET_MATCH
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::GET_MATCH);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::GET_MATCH);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+array(3) {
+ [0]=>
+ %s(3) "1,2"
+ [1]=>
+ %s(1) "1"
+ [2]=>
+ %s(1) "2"
+}
+int(2)
+array(3) {
+ [0]=>
+ %s(3) "1,2"
+ [1]=>
+ %s(1) "1"
+ [2]=>
+ %s(1) "2"
+}
+
+Notice: Array to string conversion in %siterator_050.php on line %d
+int(0)
+array(2) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(1) "1"
+}
+int(1)
+array(2) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(1) "1"
+}
+int(2)
+array(2) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(1) "1"
+}
+
+Notice: Array to string conversion in %siterator_050.php on line %d
+object(ArrayIterator)#%d (1) {
+ %s"storage"%s"ArrayIterator":private]=>
+ array(9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_051.phpt b/ext/spl/tests/iterator_051.phpt
new file mode 100644
index 0000000..2d198db
--- /dev/null
+++ b/ext/spl/tests/iterator_051.phpt
@@ -0,0 +1,96 @@
+--TEST--
+SPL: RegexIterator::GET_MATCH, USE_KEY
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::GET_MATCH, RegexIterator::USE_KEY);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::GET_MATCH, RegexIterator::USE_KEY);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "1,2"
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+string(5) "1,2,3"
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+int(1)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+string(3) "1,2"
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+string(5) "1,2,3"
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+int(0)
+array(2) {
+ [0]=>
+ string(1) "0"
+ [1]=>
+ string(1) "0"
+}
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(7) {
+ [1]=>
+ int(0)
+ ["1,2"]=>
+ int(1)
+ ["1,2,3"]=>
+ int(2)
+ [0]=>
+ int(3)
+ ["FooBar"]=>
+ int(4)
+ [","]=>
+ int(5)
+ [",,"]=>
+ int(6)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_052.phpt b/ext/spl/tests/iterator_052.phpt
new file mode 100644
index 0000000..c68bd52
--- /dev/null
+++ b/ext/spl/tests/iterator_052.phpt
@@ -0,0 +1,319 @@
+--TEST--
+SPL: RegexIterator::ALL_MATCHES
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ public $uk, $re;
+
+ function __construct($it, $re, $mode, $flags = 0)
+ {
+ $this->uk = $flags & self::USE_KEY;
+ $this->re = $re;
+ parent::__construct($it, $re, $mode, $flags);
+ }
+
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ @preg_match_all($this->re, (string)($this->uk ? $this->key() : $this->current()), $sub);
+ $ret = parent::accept();
+ var_dump($sub == $this->current());
+ return $ret;
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::ALL_MATCHES);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::ALL_MATCHES);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+int(0)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(1)
+array(3) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(3) "1,2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [2]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(2)
+array(3) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(3) "1,2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [2]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(3)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+
+Notice: Array to string conversion in %siterator_052.php on line %d
+bool(true)
+int(5)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(0)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+}
+bool(true)
+int(1)
+array(2) {
+ [0]=>
+ array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ }
+ [1]=>
+ array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(2)
+array(2) {
+ [0]=>
+ array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+ }
+ [1]=>
+ array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+ }
+}
+bool(true)
+int(3)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+
+Notice: Array to string conversion in %siterator_052.php on line %d
+bool(true)
+int(5)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_053.phpt b/ext/spl/tests/iterator_053.phpt
new file mode 100644
index 0000000..5d9c740
--- /dev/null
+++ b/ext/spl/tests/iterator_053.phpt
@@ -0,0 +1,315 @@
+--TEST--
+SPL: RegexIterator::ALL_MATCHES
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ public $uk, $re;
+
+ function __construct($it, $re, $mode, $flags = 0)
+ {
+ $this->uk = $flags & self::USE_KEY;
+ $this->re = $re;
+ parent::__construct($it, $re, $mode, $flags);
+ }
+
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ @preg_match_all($this->re, (string)($this->uk ? $this->key() : $this->current()), $sub);
+ $ret = parent::accept();
+ var_dump($sub == $this->current());
+ return $ret;
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::ALL_MATCHES, RegexIterator::USE_KEY);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::ALL_MATCHES, RegexIterator::USE_KEY);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+int(0)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(1)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(2)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(3)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(5)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(0)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "0"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "0"
+ }
+}
+bool(true)
+int(1)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+}
+bool(true)
+int(2)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(3)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "3"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "3"
+ }
+}
+bool(true)
+int(4)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "4"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "4"
+ }
+}
+bool(true)
+int(5)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "5"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "5"
+ }
+}
+bool(true)
+int(6)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "6"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "6"
+ }
+}
+bool(true)
+int(7)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "7"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "7"
+ }
+}
+bool(true)
+int(8)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "8"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "8"
+ }
+}
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_054.phpt b/ext/spl/tests/iterator_054.phpt
new file mode 100644
index 0000000..1f1cd58
--- /dev/null
+++ b/ext/spl/tests/iterator_054.phpt
@@ -0,0 +1,87 @@
+--TEST--
+SPL: RegexIterator::SPLIT
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/,/', RegexIterator::SPLIT);
+
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+}
+int(2)
+array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+}
+
+Notice: Array to string conversion in %siterator_054.php on line %d
+int(7)
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+}
+int(8)
+array(3) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+ [2]=>
+ string(0) ""
+}
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_055.phpt b/ext/spl/tests/iterator_055.phpt
new file mode 100644
index 0000000..dec68a4
--- /dev/null
+++ b/ext/spl/tests/iterator_055.phpt
@@ -0,0 +1,62 @@
+--TEST--
+SPL: RegexIterator::SPLIT, USE_KEY
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::SPLIT, RegexIterator::USE_KEY);
+
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "1,2"
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+}
+string(5) "1,2,3"
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(2) ",3"
+}
+object(ArrayIterator)#%d (1) {
+ ["storage":"ArrayIterator":private]=>
+ array(7) {
+ [1]=>
+ int(0)
+ ["1,2"]=>
+ int(1)
+ ["1,2,3"]=>
+ int(2)
+ [0]=>
+ int(3)
+ ["FooBar"]=>
+ int(4)
+ [","]=>
+ int(5)
+ [",,"]=>
+ int(6)
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_056.phpt b/ext/spl/tests/iterator_056.phpt
new file mode 100644
index 0000000..4b0e75a
--- /dev/null
+++ b/ext/spl/tests/iterator_056.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: FilterIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myFilterIterator extends FilterIterator {
+ function accept() {
+
+ }
+}
+try {
+ $it = new myFilterIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_057.phpt b/ext/spl/tests/iterator_057.phpt
new file mode 100644
index 0000000..602c125
--- /dev/null
+++ b/ext/spl/tests/iterator_057.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: ArrayIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+/**
+ * From Docs: Construct a new array iterator from anything that has a hash table.
+ * NULL, NOTHING is not a hash table ;)
+ */
+class myArrayIterator extends ArrayIterator {
+}
+try {
+ $it = new myArrayIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+echo 'no Exception thrown'
+?>
+--EXPECT--
+no Exception thrown
diff --git a/ext/spl/tests/iterator_058.phpt b/ext/spl/tests/iterator_058.phpt
new file mode 100644
index 0000000..3f65ecb
--- /dev/null
+++ b/ext/spl/tests/iterator_058.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: Iterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myIterator implements Iterator {
+
+ function current() {}
+ function next() {}
+ function key() {}
+ function valid() {}
+ function rewind() {}
+
+}
+try {
+ $it = new myIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+echo 'no Exception thrown';
+?>
+--EXPECT--
+no Exception thrown
diff --git a/ext/spl/tests/iterator_059.phpt b/ext/spl/tests/iterator_059.phpt
new file mode 100644
index 0000000..8c579ae
--- /dev/null
+++ b/ext/spl/tests/iterator_059.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: CachingIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myCachingIterator extends CachingIterator {
+
+}
+try {
+ $it = new myCachingIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_060.phpt b/ext/spl/tests/iterator_060.phpt
new file mode 100644
index 0000000..0c3b6c2
--- /dev/null
+++ b/ext/spl/tests/iterator_060.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: RecursiveCachingIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myRecursiveCachingIterator extends RecursiveCachingIterator {
+
+}
+try {
+ $it = new myRecursiveCachingIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_061.phpt b/ext/spl/tests/iterator_061.phpt
new file mode 100644
index 0000000..472f8da
--- /dev/null
+++ b/ext/spl/tests/iterator_061.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: ParentIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myParentIterator extends ParentIterator {
+
+}
+try {
+ $it = new myParentIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_062.phpt b/ext/spl/tests/iterator_062.phpt
new file mode 100644
index 0000000..59a1dfa
--- /dev/null
+++ b/ext/spl/tests/iterator_062.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: RecursiveIteratorIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+}
+
+try {
+ $it = new myRecursiveIteratorIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_063.phpt b/ext/spl/tests/iterator_063.phpt
new file mode 100644
index 0000000..4d4112b
--- /dev/null
+++ b/ext/spl/tests/iterator_063.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: LimitIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myLimitIterator extends LimitIterator {
+
+}
+try {
+ $it = new myLimitIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_064.phpt b/ext/spl/tests/iterator_064.phpt
new file mode 100644
index 0000000..6a62e6c
--- /dev/null
+++ b/ext/spl/tests/iterator_064.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: CachingIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myCachingIterator extends CachingIterator {}
+try {
+ $it = new myCachingIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_065.phpt b/ext/spl/tests/iterator_065.phpt
new file mode 100644
index 0000000..9ea2974
--- /dev/null
+++ b/ext/spl/tests/iterator_065.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: RecursiveCachingIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myRecursiveCachingIterator extends RecursiveCachingIterator {}
+try {
+ $it = new myRecursiveCachingIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_066.phpt b/ext/spl/tests/iterator_066.phpt
new file mode 100644
index 0000000..008c47c
--- /dev/null
+++ b/ext/spl/tests/iterator_066.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: NoRewindIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myNoRewindIterator extends NoRewindIterator {}
+try {
+ $it = new myNoRewindIterator();
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+InvalidArgumentException thrown
diff --git a/ext/spl/tests/iterator_067.phpt b/ext/spl/tests/iterator_067.phpt
new file mode 100644
index 0000000..e05a48d
--- /dev/null
+++ b/ext/spl/tests/iterator_067.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: AppendIterator::__construct(void)
+--CREDITS--
+Sebastian Schürmann
+--FILE--
+<?php
+class myAppendIterator extends AppendIterator {}
+try {
+ $it = new myAppendIterator();
+ echo "no exception";
+} catch (InvalidArgumentException $e) {
+ echo 'InvalidArgumentException thrown';
+}
+?>
+--EXPECT--
+no exception
diff --git a/ext/spl/tests/iterator_068.phpt b/ext/spl/tests/iterator_068.phpt
new file mode 100644
index 0000000..4845708
--- /dev/null
+++ b/ext/spl/tests/iterator_068.phpt
@@ -0,0 +1,34 @@
+--TEST--
+SPL: Iterator: Overloaded object and destruction
+--FILE--
+<?php
+
+class Test implements Iterator {
+ function foo() {
+ echo __METHOD__ . "()\n";
+ }
+ function rewind() {}
+ function valid() {}
+ function current() {}
+ function key() {}
+ function next() {}
+}
+
+class TestIteratorIterator extends IteratorIterator {
+ function __destruct() {
+ echo __METHOD__ . "()\n";
+ $this->foo();
+ }
+}
+
+$obj = new TestIteratorIterator(new Test);
+$obj->foo();
+unset($obj);
+
+?>
+===DONE===
+--EXPECT--
+Test::foo()
+TestIteratorIterator::__destruct()
+Test::foo()
+===DONE===
diff --git a/ext/spl/tests/iterator_069.phpt b/ext/spl/tests/iterator_069.phpt
new file mode 100644
index 0000000..e9b3177
--- /dev/null
+++ b/ext/spl/tests/iterator_069.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: RecursiveIteratorIterator cannot be used with foreach by reference
+--FILE--
+<?php
+
+$arr = array(array(1,2));
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+$recItIt = new RecursiveIteratorIterator($recArrIt);
+
+foreach ($recItIt as &$val) echo "$val\n";
+
+?>
+--EXPECTF--
+Fatal error: An iterator cannot be used with foreach by reference in %s on line %d
diff --git a/ext/spl/tests/iterator_070.phpt b/ext/spl/tests/iterator_070.phpt
new file mode 100644
index 0000000..c45f08e
--- /dev/null
+++ b/ext/spl/tests/iterator_070.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Ensure that non-overriden methods execute problem free.
+--FILE--
+<?php
+
+$array = array();
+$recArrIt = new RecursiveArrayIterator($array);
+
+$recItIt = new RecursiveIteratorIterator($recArrIt);
+
+var_dump($recItIt->beginIteration());
+var_dump($recItIt->endIteration());
+var_dump($recItIt->nextElement());
+
+?>
+
+--EXPECTF--
+NULL
+NULL
+NULL \ No newline at end of file
diff --git a/ext/spl/tests/iterator_071.phpt b/ext/spl/tests/iterator_071.phpt
new file mode 100644
index 0000000..21ec798
--- /dev/null
+++ b/ext/spl/tests/iterator_071.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Test where the case is RS_SELF and mode is CHILD_FIRST
+--FILE--
+<?php
+
+$arr = array(array(1,2),2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function nextelement() {
+ echo __METHOD__."\n";
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::CHILD_FIRST);
+
+foreach ($recItIt as $key => $val) echo "$key\n";
+
+?>
+--EXPECTF--
+MyRecursiveIteratorIterator::nextelement
+0
+MyRecursiveIteratorIterator::nextelement
+1
+MyRecursiveIteratorIterator::nextelement
+0
+MyRecursiveIteratorIterator::nextelement
+1 \ No newline at end of file
diff --git a/ext/spl/tests/iterator_count.phpt b/ext/spl/tests/iterator_count.phpt
new file mode 100644
index 0000000..9aa4e11
--- /dev/null
+++ b/ext/spl/tests/iterator_count.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: iterator_count() exceptions test
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$array=array('a','b');
+
+$iterator = new ArrayIterator($array);
+
+iterator_count();
+
+
+iterator_count($iterator,'1');
+
+iterator_count('1');
+
+
+?>
+--EXPECTF--
+Warning: iterator_count() expects exactly 1 parameter, 0 given in %s
+
+Warning: iterator_count() expects exactly 1 parameter, 2 given in %s
+
+Catchable fatal error: Argument 1 passed to iterator_count() must implement interface Traversable, %unicode_string_optional% given %s
diff --git a/ext/spl/tests/iterator_to_array.phpt b/ext/spl/tests/iterator_to_array.phpt
new file mode 100644
index 0000000..958d370
--- /dev/null
+++ b/ext/spl/tests/iterator_to_array.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: iterator_to_array() exceptions test
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$array=array('a','b');
+
+$iterator = new ArrayIterator($array);
+
+iterator_to_array();
+
+
+iterator_to_array($iterator,'test','test');
+
+iterator_to_array('test','test');
+
+?>
+--EXPECTF--
+Warning: iterator_to_array() expects at least 1 parameter, 0 given in %s
+
+Warning: iterator_to_array() expects at most 2 parameters, 3 given in %s
+
+Catchable fatal error: Argument 1 passed to iterator_to_array() must implement interface Traversable, %unicode_string_optional% given %s
diff --git a/ext/spl/tests/limititerator_seek.phpt b/ext/spl/tests/limititerator_seek.phpt
new file mode 100644
index 0000000..a59a49b
--- /dev/null
+++ b/ext/spl/tests/limititerator_seek.phpt
@@ -0,0 +1,18 @@
+--TEST--
+SPL: LimitIterator seek() arguments
+--CREDITS--
+Roshan Abraham (roshanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+
+$a = array(1,2,3);
+$lt = new LimitIterator(new ArrayIterator($a));
+
+$lt->seek(1,1); // Should throw a warning as seek expects only 1 argument
+
+?>
+--EXPECTF--
+
+Warning: LimitIterator::seek() expects exactly 1 parameter, 2 given in %s on line %d
+
diff --git a/ext/spl/tests/multiple_iterator_001.phpt b/ext/spl/tests/multiple_iterator_001.phpt
new file mode 100644
index 0000000..edd03f5
--- /dev/null
+++ b/ext/spl/tests/multiple_iterator_001.phpt
@@ -0,0 +1,345 @@
+--TEST--
+SPL: MultipleIterator
+--FILE--
+<?php
+
+$iter1 = new ArrayIterator(array(1,2,3));
+$iter2 = new ArrayIterator(array(1,2));
+$iter3 = new ArrayIterator(array(new stdClass(),"string",3));
+
+$m = new MultipleIterator();
+
+echo "-- Default flags, no iterators --\n";
+foreach($m as $value) {
+ var_dump($value);
+}
+var_dump($m->current());
+
+$m->attachIterator($iter1);
+$m->attachIterator($iter2);
+$m->attachIterator($iter3);
+
+echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --\n";
+
+var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC));
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+try {
+ $m->current();
+} catch(RuntimeException $e) {
+ echo "RuntimeException thrown: " . $e->getMessage() . "\n";
+}
+try {
+ $m->key();
+} catch(RuntimeException $e) {
+ echo "RuntimeException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC);
+var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC));
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Default flags, added element --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC);
+
+$iter2[] = 3;
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_ASSOC);
+$m->rewind();
+try {
+ $m->current();
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --\n";
+
+$m->attachIterator($iter1, "iter1");
+$m->attachIterator($iter2, b"iter2");
+$m->attachIterator($iter3, 3);
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Associate with invalid value --\n";
+
+try {
+ $m->attachIterator($iter3, new stdClass());
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Associate with duplicate value --\n";
+
+try {
+ $m->attachIterator($iter3, "iter1");
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Count, contains, detach, count, contains, iterate --\n";
+
+var_dump($m->countIterators());
+var_dump($m->containsIterator($iter2));
+var_dump($m->detachIterator($iter2));
+var_dump($m->countIterators());
+var_dump($m->containsIterator($iter2));
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+?>
+--EXPECTF--
+-- Default flags, no iterators --
+bool(false)
+-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --
+bool(true)
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ string(6) "string"
+}
+RuntimeException thrown: Called current() with non valid sub iterator
+RuntimeException thrown: Called key() with non valid sub iterator
+-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --
+bool(true)
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ string(6) "string"
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ NULL
+ [2]=>
+ int(2)
+}
+array(3) {
+ [0]=>
+ int(3)
+ [1]=>
+ NULL
+ [2]=>
+ int(3)
+}
+-- Default flags, added element --
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ string(6) "string"
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ int(2)
+}
+array(3) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(3)
+ [2]=>
+ int(3)
+}
+-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --
+InvalidArgumentException thrown: Sub-Iterator is associated with NULL
+-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --
+array(3) {
+ ["iter1"]=>
+ int(0)
+ ["iter2"]=>
+ int(0)
+ [3]=>
+ int(0)
+}
+array(3) {
+ ["iter1"]=>
+ int(1)
+ ["iter2"]=>
+ int(1)
+ [3]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ ["iter1"]=>
+ int(1)
+ ["iter2"]=>
+ int(1)
+ [3]=>
+ int(1)
+}
+array(3) {
+ ["iter1"]=>
+ int(2)
+ ["iter2"]=>
+ int(2)
+ [3]=>
+ string(6) "string"
+}
+array(3) {
+ ["iter1"]=>
+ int(2)
+ ["iter2"]=>
+ int(2)
+ [3]=>
+ int(2)
+}
+array(3) {
+ ["iter1"]=>
+ int(3)
+ ["iter2"]=>
+ int(3)
+ [3]=>
+ int(3)
+}
+-- Associate with invalid value --
+InvalidArgumentException thrown: Info must be NULL, integer or string
+-- Associate with duplicate value --
+InvalidArgumentException thrown: Key duplication error
+-- Count, contains, detach, count, contains, iterate --
+int(3)
+bool(true)
+NULL
+int(2)
+bool(false)
+array(2) {
+ ["iter1"]=>
+ int(0)
+ [3]=>
+ int(0)
+}
+array(2) {
+ ["iter1"]=>
+ int(1)
+ [3]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(2) {
+ ["iter1"]=>
+ int(1)
+ [3]=>
+ int(1)
+}
+array(2) {
+ ["iter1"]=>
+ int(2)
+ [3]=>
+ string(6) "string"
+}
+array(2) {
+ ["iter1"]=>
+ int(2)
+ [3]=>
+ int(2)
+}
+array(2) {
+ ["iter1"]=>
+ int(3)
+ [3]=>
+ int(3)
+}
diff --git a/ext/spl/tests/observer_001.phpt b/ext/spl/tests/observer_001.phpt
new file mode 100644
index 0000000..e7d72b9
--- /dev/null
+++ b/ext/spl/tests/observer_001.phpt
@@ -0,0 +1,116 @@
+--TEST--
+SPL: SplObserver and SplSubject (empty notify)
+--FILE--
+<?php
+
+class ObserverImpl implements SplObserver
+{
+ protected $name = '';
+
+ function __construct($name = 'obj')
+ {
+ $this->name = '$' . $name;
+ }
+
+ function update(SplSubject $subject)
+ {
+ echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n";
+ }
+
+ function getName()
+ {
+ return $this->name;
+ }
+}
+
+class SubjectImpl implements SplSubject
+{
+ protected $name = '';
+ protected $observers = array();
+
+ function __construct($name = 'sub')
+ {
+ $this->name = '$' . $name;
+ }
+
+ function attach(SplObserver $observer)
+ {
+ echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n";
+ if (!in_array($observer, $this->observers))
+ {
+ $this->observers[] = $observer;
+ }
+ }
+
+ function detach(SplObserver $observer)
+ {
+ echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n";
+ $idx = array_search($observer, $this->observers);
+ if ($idx !== false)
+ {
+ unset($this->observers[$idx]);
+ }
+ }
+
+ function notify()
+ {
+ echo '$sub->' . __METHOD__ . "();\n";
+ foreach($this->observers as $observer)
+ {
+ $observer->update($this);
+ }
+ }
+
+ function getName()
+ {
+ return $this->name;
+ }
+}
+
+$sub = new SubjectImpl;
+
+$ob1 = new ObserverImpl("ob1");
+$ob2 = new ObserverImpl("ob2");
+$ob3 = new ObserverImpl("ob3");
+
+$sub->attach($ob1);
+$sub->attach($ob1);
+$sub->attach($ob2);
+$sub->attach($ob3);
+
+$sub->notify();
+
+$sub->detach($ob3);
+
+$sub->notify();
+
+$sub->detach($ob2);
+$sub->detach($ob1);
+
+$sub->notify();
+
+$sub->attach($ob3);
+
+$sub->notify();
+?>
+===DONE===
+--EXPECT--
+$sub->SubjectImpl::attach($ob1);
+$sub->SubjectImpl::attach($ob1);
+$sub->SubjectImpl::attach($ob2);
+$sub->SubjectImpl::attach($ob3);
+$sub->SubjectImpl::notify();
+$ob1->ObserverImpl::update($sub);
+$ob2->ObserverImpl::update($sub);
+$ob3->ObserverImpl::update($sub);
+$sub->SubjectImpl::detach($ob3);
+$sub->SubjectImpl::notify();
+$ob1->ObserverImpl::update($sub);
+$ob2->ObserverImpl::update($sub);
+$sub->SubjectImpl::detach($ob2);
+$sub->SubjectImpl::detach($ob1);
+$sub->SubjectImpl::notify();
+$sub->SubjectImpl::attach($ob3);
+$sub->SubjectImpl::notify();
+$ob3->ObserverImpl::update($sub);
+===DONE===
diff --git a/ext/spl/tests/observer_002.phpt b/ext/spl/tests/observer_002.phpt
new file mode 100644
index 0000000..5d00617
--- /dev/null
+++ b/ext/spl/tests/observer_002.phpt
@@ -0,0 +1,199 @@
+--TEST--
+SPL: SplObjectStorage
+--FILE--
+<?php
+
+class MyObjectStorage extends SplObjectStorage
+{
+ function rewind()
+ {
+ echo __METHOD__ . "()\n";
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "(" . (parent::valid() ? 1 : 0) . ")\n";
+ return parent::valid();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "(" . parent::key() . ")\n";
+ return parent::key();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "(" . parent::current()->getName() . ")\n";
+ return parent::current();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "()\n";
+ parent::next();
+ }
+}
+
+class ObserverImpl implements SplObserver
+{
+ protected $name = '';
+
+ function __construct($name = 'obj')
+ {
+ $this->name = '$' . $name;
+ }
+
+ function update(SplSubject $subject)
+ {
+ echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n";
+ }
+
+ function getName()
+ {
+ return $this->name;
+ }
+}
+
+class SubjectImpl implements SplSubject
+{
+ protected $name = '';
+ protected $observers;
+
+ function __construct($name = 'sub')
+ {
+ $this->observers = new MyObjectStorage;
+ $this->name = '$' . $name;
+ }
+
+ function attach(SplObserver $observer)
+ {
+ echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n";
+ $this->observers->attach($observer);
+ }
+
+ function detach(SplObserver $observer)
+ {
+ echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n";
+ $this->observers->detach($observer);
+ }
+
+ function count()
+ {
+ return $this->observers->count();
+ }
+
+ function notify()
+ {
+ echo $this->name . '->' . __METHOD__ . "();\n";
+ foreach($this->observers as $key => $observer)
+ {
+ $observer->update($this);
+ }
+ }
+
+ function getName()
+ {
+ return $this->name;
+ }
+
+ function contains($obj)
+ {
+ return $this->observers->contains($obj);
+ }
+}
+
+$sub = new SubjectImpl;
+
+$ob1 = new ObserverImpl("ob1");
+$ob2 = new ObserverImpl("ob2");
+$ob3 = new ObserverImpl("ob3");
+
+var_dump($sub->contains($ob1));
+$sub->attach($ob1);
+var_dump($sub->contains($ob1));
+$sub->attach($ob1);
+$sub->attach($ob2);
+$sub->attach($ob3);
+var_dump($sub->count());
+
+$sub->notify();
+
+$sub->detach($ob3);
+var_dump($sub->count());
+
+$sub->notify();
+
+$sub->detach($ob2);
+$sub->detach($ob1);
+var_dump($sub->count());
+
+$sub->notify();
+
+$sub->attach($ob3);
+var_dump($sub->count());
+
+$sub->notify();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+bool(false)
+$sub->SubjectImpl::attach($ob1);
+bool(true)
+$sub->SubjectImpl::attach($ob1);
+$sub->SubjectImpl::attach($ob2);
+$sub->SubjectImpl::attach($ob3);
+int(3)
+$sub->SubjectImpl::notify();
+MyObjectStorage::rewind()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob1)
+MyObjectStorage::key(0)
+$ob1->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob2)
+MyObjectStorage::key(1)
+$ob2->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob3)
+MyObjectStorage::key(2)
+$ob3->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(0)
+$sub->SubjectImpl::detach($ob3);
+int(2)
+$sub->SubjectImpl::notify();
+MyObjectStorage::rewind()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob1)
+MyObjectStorage::key(0)
+$ob1->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob2)
+MyObjectStorage::key(1)
+$ob2->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(0)
+$sub->SubjectImpl::detach($ob2);
+$sub->SubjectImpl::detach($ob1);
+int(0)
+$sub->SubjectImpl::notify();
+MyObjectStorage::rewind()
+MyObjectStorage::valid(0)
+$sub->SubjectImpl::attach($ob3);
+int(1)
+$sub->SubjectImpl::notify();
+MyObjectStorage::rewind()
+MyObjectStorage::valid(1)
+MyObjectStorage::current($ob3)
+MyObjectStorage::key(0)
+$ob3->ObserverImpl::update($sub);
+MyObjectStorage::next()
+MyObjectStorage::valid(0)
+===DONE===
diff --git a/ext/spl/tests/observer_003.phpt b/ext/spl/tests/observer_003.phpt
new file mode 100644
index 0000000..5e5da22
--- /dev/null
+++ b/ext/spl/tests/observer_003.phpt
@@ -0,0 +1,58 @@
+--TEST--
+SPL: SplObjectStorage serialization
+--FILE--
+<?php
+
+class TestClass
+{
+ public $test = 25;
+
+ public function __construct($test = 42)
+ {
+ $this->test = $test;
+ }
+}
+
+$storage = new SplObjectStorage();
+
+foreach(array(1,"2","foo",true) as $value)
+{
+ $storage->attach(new TestClass($value));
+}
+
+var_dump(count($storage));
+
+foreach($storage as $object)
+{
+ var_dump($object->test);
+}
+
+var_dump(serialize($storage));
+echo "===UNSERIALIZE===\n";
+
+$storage2 = unserialize(serialize($storage));
+
+var_dump(count($storage2));
+
+foreach($storage2 as $object)
+{
+ var_dump($object->test);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(4)
+int(1)
+string(1) "2"
+string(3) "foo"
+bool(true)
+string(%d) "%s"
+===UNSERIALIZE===
+int(4)
+int(1)
+string(1) "2"
+string(3) "foo"
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/observer_004.phpt b/ext/spl/tests/observer_004.phpt
new file mode 100644
index 0000000..0bc2512
--- /dev/null
+++ b/ext/spl/tests/observer_004.phpt
@@ -0,0 +1,122 @@
+--TEST--
+SPL: SplObjectStorage serialization & overloading
+--FILE--
+<?php
+
+class TestClass
+{
+ public $test = 25;
+
+ public function __construct($test = 42)
+ {
+ $this->test = $test;
+ }
+}
+
+class MyStorage extends SplObjectStorage
+{
+ public $bla = 25;
+
+ public function __construct($bla = 26)
+ {
+ $this->bla = $bla;
+ }
+}
+
+$storage = new MyStorage();
+
+foreach(array(1,2) as $value)
+{
+ $storage->attach(new TestClass($value));
+}
+
+var_dump(count($storage));
+
+foreach($storage as $object)
+{
+ var_dump($object->test);
+}
+
+var_dump($storage);
+
+var_dump(serialize($storage));
+echo "===UNSERIALIZE===\n";
+
+$storage2 = unserialize(serialize($storage));
+
+var_dump(count($storage2));
+
+foreach($storage2 as $object)
+{
+ var_dump($object->test);
+}
+
+var_dump($storage2);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ NULL
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ NULL
+ }
+ }
+}
+string(%d) "%s"
+===UNSERIALIZE===
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ NULL
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ NULL
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/observer_005.phpt b/ext/spl/tests/observer_005.phpt
new file mode 100644
index 0000000..883602f
--- /dev/null
+++ b/ext/spl/tests/observer_005.phpt
@@ -0,0 +1,212 @@
+--TEST--
+SPL: SplObjectStorage serialization & visibility
+--FILE--
+<?php
+
+class TestClass
+{
+ public $def = 24;
+ public $pub = 25;
+ protected $pro = 26;
+ private $pri = 27;
+
+ public function __construct($pub = 42, $pro = 43, $pri = 44)
+ {
+ $this->pub = $pub;
+ $this->pro = $pro;
+ $this->pri = $pri;
+ }
+}
+
+class ExtTestClass
+{
+}
+
+class MyStorage extends SplObjectStorage
+{
+ public $def = 24;
+ public $pub = 25;
+ protected $pro = 26;
+ private $pri = 27;
+
+ public function __construct($pub = 52, $pro = 53, $pri = 54)
+ {
+ $this->pub = $pub;
+ $this->pro = $pro;
+ $this->pri = $pri;
+ }
+}
+
+class ExtStorage extends MyStorage
+{
+}
+
+$storage = new MyStorage(1,2,3);
+
+foreach(array(array(4,5,6),array(7,8,9)) as $value)
+{
+ $storage->attach(new TestClass($value[0], $value[1], $value[2]));
+}
+
+var_dump(count($storage));
+
+foreach($storage as $object)
+{
+ var_dump($object);
+}
+
+var_dump($storage);
+
+var_dump(serialize($storage));
+echo "===UNSERIALIZE===\n";
+
+$storage2 = unserialize(serialize($storage));
+
+var_dump(count($storage2));
+
+foreach($storage2 as $object)
+{
+ var_dump($object);
+}
+
+var_dump($storage2);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(2)
+object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(4)
+ ["pro":protected]=>
+ int(5)
+ ["pri":"TestClass":private]=>
+ int(6)
+}
+object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(7)
+ ["pro":protected]=>
+ int(8)
+ ["pri":"TestClass":private]=>
+ int(9)
+}
+object(MyStorage)#%d (5) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(1)
+ ["pro":protected]=>
+ int(2)
+ ["pri":"MyStorage":private]=>
+ int(3)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(4)
+ ["pro":protected]=>
+ int(5)
+ ["pri":"TestClass":private]=>
+ int(6)
+ }
+ ["inf"]=>
+ NULL
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(7)
+ ["pro":protected]=>
+ int(8)
+ ["pri":"TestClass":private]=>
+ int(9)
+ }
+ ["inf"]=>
+ NULL
+ }
+ }
+}
+string(%d) "%s"
+===UNSERIALIZE===
+int(2)
+object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(4)
+ ["pro":protected]=>
+ int(5)
+ ["pri":"TestClass":private]=>
+ int(6)
+}
+object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(7)
+ ["pro":protected]=>
+ int(8)
+ ["pri":"TestClass":private]=>
+ int(9)
+}
+object(MyStorage)#%d (5) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(1)
+ ["pro":protected]=>
+ int(2)
+ ["pri":"MyStorage":private]=>
+ int(3)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(4)
+ ["pro":protected]=>
+ int(5)
+ ["pri":"TestClass":private]=>
+ int(6)
+ }
+ ["inf"]=>
+ NULL
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (4) {
+ ["def"]=>
+ int(24)
+ ["pub"]=>
+ int(7)
+ ["pro":protected]=>
+ int(8)
+ ["pri":"TestClass":private]=>
+ int(9)
+ }
+ ["inf"]=>
+ NULL
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/observer_006.phpt b/ext/spl/tests/observer_006.phpt
new file mode 100644
index 0000000..3cd84a7
--- /dev/null
+++ b/ext/spl/tests/observer_006.phpt
@@ -0,0 +1,310 @@
+--TEST--
+SPL: SplObjectStorage with accociatied information
+--FILE--
+<?php
+
+class TestClass
+{
+ public $test = 25;
+
+ public function __construct($test = 42)
+ {
+ $this->test = $test;
+ }
+}
+
+class MyStorage extends SplObjectStorage
+{
+ public $bla = 25;
+
+ public function __construct($bla = 26)
+ {
+ $this->bla = $bla;
+ }
+}
+
+$storage = new MyStorage();
+
+foreach(array(1=>"foo",2=>42) as $key => $value)
+{
+ $storage->attach(new TestClass($key), $value);
+}
+
+var_dump(count($storage));
+
+foreach($storage as $object)
+{
+ var_dump($object->test);
+}
+
+var_dump($storage);
+
+var_dump(serialize($storage));
+echo "===UNSERIALIZE===\n";
+
+$storage2 = unserialize(serialize($storage));
+
+var_dump(count($storage2));
+
+foreach($storage2 as $object)
+{
+ var_dump($object->test);
+}
+
+var_dump($storage2);
+$storage->attach(new TestClass(3), new stdClass);
+$storage->attach(new TestClass(4), new TestClass(5));
+echo "===UNSERIALIZE2===\n";
+var_dump(unserialize(serialize($storage)));
+$storage->rewind();
+$storage->next();
+var_dump($storage->key());
+var_dump($storage->current());
+var_dump($storage->getInfo());
+$storage->setInfo("bar");
+var_dump($storage->getInfo());
+echo "===UNSERIALIZE3===\n";
+var_dump(unserialize(serialize($storage)));
+$storage->rewind();
+$storage->next();
+$storage->next();
+var_dump($storage->key());
+var_dump($storage->current());
+$storage->attach($storage->current(), "replaced");
+echo "===UNSERIALIZE4===\n";
+var_dump(unserialize(serialize($storage)));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ string(3) "foo"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ int(42)
+ }
+ }
+}
+string(%d) "%s"
+===UNSERIALIZE===
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(2) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ string(3) "foo"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ int(42)
+ }
+ }
+}
+===UNSERIALIZE2===
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(4) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ string(3) "foo"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ int(42)
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(3)
+ }
+ ["inf"]=>
+ object(stdClass)#%d (0) {
+ }
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(4)
+ }
+ ["inf"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(5)
+ }
+ }
+ }
+}
+int(1)
+object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+}
+int(42)
+string(3) "bar"
+===UNSERIALIZE3===
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(4) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ string(3) "foo"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ string(3) "bar"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(3)
+ }
+ ["inf"]=>
+ object(stdClass)#%d (0) {
+ }
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(4)
+ }
+ ["inf"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(5)
+ }
+ }
+ }
+}
+int(2)
+object(TestClass)#7 (1) {
+ ["test"]=>
+ int(3)
+}
+===UNSERIALIZE4===
+object(MyStorage)#%d (2) {
+ ["bla"]=>
+ int(26)
+ ["storage":"SplObjectStorage":private]=>
+ array(4) {
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(1)
+ }
+ ["inf"]=>
+ string(3) "foo"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(2)
+ }
+ ["inf"]=>
+ string(3) "bar"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(3)
+ }
+ ["inf"]=>
+ string(8) "replaced"
+ }
+ ["%s"]=>
+ array(2) {
+ ["obj"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(4)
+ }
+ ["inf"]=>
+ object(TestClass)#%d (1) {
+ ["test"]=>
+ int(5)
+ }
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/observer_007.phpt b/ext/spl/tests/observer_007.phpt
new file mode 100644
index 0000000..e494f19
--- /dev/null
+++ b/ext/spl/tests/observer_007.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplObjectStorage comapred with ==
+--FILE--
+<?php
+$a = new SplObjectStorage;
+$b = new SplObjectStorage;
+var_dump($a == $b);
+$b[$b] = 2;
+var_dump($a == $b);
+$a[$b] = 2;
+var_dump($a == $b);
+$a[$b] = 3;
+var_dump($a == $b);
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/observer_008.phpt b/ext/spl/tests/observer_008.phpt
new file mode 100644
index 0000000..56a3c89
--- /dev/null
+++ b/ext/spl/tests/observer_008.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SPL: SplObjectStorage addAll/removeAll
+--FILE--
+<?php
+class A extends SplObjectStorage { }
+
+$o1 = new StdClass;
+$o2 = new StdClass;
+$o3 = new StdClass;
+
+$a = new A;
+$a->attach($o1);
+$a->attach($o2);
+
+$b = new SplObjectSTorage();
+$b->attach($o2);
+$b->attach($o3);
+
+$a->addAll($b);
+
+var_dump($a->count());
+
+$a->detach($o3);
+var_dump($a->count());
+
+$a->removeAll($b);
+var_dump($a->count());
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(3)
+int(2)
+int(1)
+===DONE===
diff --git a/ext/spl/tests/observer_009.phpt b/ext/spl/tests/observer_009.phpt
new file mode 100644
index 0000000..6ac676c
--- /dev/null
+++ b/ext/spl/tests/observer_009.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: SplObjectStorage addAll/removeAll
+--FILE--
+<?php
+class Foo {}
+
+$storageA = new \SplObjectStorage();
+$storageA->attach(new \Foo);
+$storageA->attach(new \Foo);
+
+echo ("Count storage A: " . count($storageA));
+foreach ($storageA as $object) {
+ echo ' x ';
+}
+
+echo "\n";
+$storageB = clone $storageA;
+
+echo ("Count storage B: " . count($storageB));
+foreach ($storageB as $object) {
+ echo ' x ';
+}
+echo "\n";
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Count storage A: 2 x x
+Count storage B: 2 x x
+===DONE===
diff --git a/ext/spl/tests/pqueue_001.phpt b/ext/spl/tests/pqueue_001.phpt
new file mode 100644
index 0000000..de164e5
--- /dev/null
+++ b/ext/spl/tests/pqueue_001.phpt
@@ -0,0 +1,96 @@
+--TEST--
+SPL: SplPriorityQueue: std operations and extract flags
+--FILE--
+<?php
+$pq = new SplPriorityQueue();
+
+// errors
+try {
+ $pq->extract();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+$pq->insert("a", 1);
+$pq->insert("b", 2);
+$pq->insert("c", 0);
+
+foreach ($pq as $k=>$v) {
+ echo "$k=>".print_r($v, 1)."\n";
+}
+
+echo "EXTR_BOTH\n";
+
+$pq1 = new SplPriorityQueue();
+$pq1->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
+
+$pq1->insert("a", 1);
+$pq1->insert("b", 2);
+$pq1->insert("c", 0);
+
+foreach ($pq1 as $k=>$v) {
+ echo "$k=>".print_r($v, 1)."\n";
+}
+
+echo "EXTR_DATA\n";
+
+$pq2 = new SplPriorityQueue();
+$pq2->setExtractFlags(SplPriorityQueue::EXTR_DATA);
+
+$pq2->insert("a", 1);
+$pq2->insert("b", 2);
+$pq2->insert("c", 0);
+
+foreach ($pq2 as $k=>$v) {
+ echo "$k=>".print_r($v, 1)."\n";
+}
+
+echo "EXTR_PRIORITY\n";
+
+$pq3 = new SplPriorityQueue();
+$pq3->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
+
+$pq3->insert("a", 1);
+$pq3->insert("b", 2);
+$pq3->insert("c", 0);
+
+foreach ($pq3 as $k=>$v) {
+ echo "$k=>".print_r($v, 1)."\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Can't extract from an empty heap
+2=>b
+1=>a
+0=>c
+EXTR_BOTH
+2=>Array
+(
+ [data] => b
+ [priority] => 2
+)
+
+1=>Array
+(
+ [data] => a
+ [priority] => 1
+)
+
+0=>Array
+(
+ [data] => c
+ [priority] => 0
+)
+
+EXTR_DATA
+2=>b
+1=>a
+0=>c
+EXTR_PRIORITY
+2=>2
+1=>1
+0=>0
+===DONE===
diff --git a/ext/spl/tests/pqueue_002.phpt b/ext/spl/tests/pqueue_002.phpt
new file mode 100644
index 0000000..eaab2cf
--- /dev/null
+++ b/ext/spl/tests/pqueue_002.phpt
@@ -0,0 +1,67 @@
+--TEST--
+SPL: SplPriorityQueue: exceptions
+--FILE--
+<?php
+class myPQueue extends SplPriorityQueue {
+ public function compare($a, $b) {
+ throw new exception("foo");
+ }
+}
+
+$h = new myPQueue;
+
+try {
+ $h->insert(1, 1);
+ echo "inserted 1\n";
+ $h->insert(2, 1);
+ echo "inserted 2\n";
+ $h->insert(3, 1);
+ echo "inserted 3\n";
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ $h->insert(4, 1);
+ echo "inserted 4\n";
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+
+echo "Recovering..\n";
+$h->recoverFromCorruption();
+
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+try {
+ var_dump($h->extract());
+} catch(Exception $e) {
+ echo "Exception: ".$e->getMessage()."\n";
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+inserted 1
+Exception: foo
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Exception: Heap is corrupted, heap properties are no longer ensured.
+Recovering..
+int(1)
+int(2)
+===DONE===
diff --git a/ext/spl/tests/pqueue_003.phpt b/ext/spl/tests/pqueue_003.phpt
new file mode 100644
index 0000000..9c0b5a5
--- /dev/null
+++ b/ext/spl/tests/pqueue_003.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplPriorityQueue: iteration through methods
+--FILE--
+<?php
+$h = new SplPriorityQueue();
+
+$h->insert(1, 1);
+$h->insert(5, 5);
+$h->insert(0, 0);
+$h->insert(4, 4);
+
+$h->rewind();
+echo "count(\$h) = ".count($h)."\n";
+echo "\$h->count() = ".$h->count()."\n";
+while ($h->valid()) {
+ $k = $h->key();
+ $v = $h->current();
+ echo "$k=>$v\n";
+ $h->next();
+}
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+count($h) = 4
+$h->count() = 4
+3=>5
+2=>4
+1=>1
+0=>0
+===DONE===
diff --git a/ext/spl/tests/pqueue_004.phpt b/ext/spl/tests/pqueue_004.phpt
new file mode 100644
index 0000000..3a86f9e
--- /dev/null
+++ b/ext/spl/tests/pqueue_004.phpt
@@ -0,0 +1,54 @@
+--TEST--
+SPL: SplPriorityQueue: var_dump
+--FILE--
+<?php
+$pq = new SplPriorityQueue();
+
+$pq->insert("a", 0);
+$pq->insert("b", 1);
+$pq->insert("c", 5);
+$pq->insert("d", -2);
+
+var_dump($pq);
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(SplPriorityQueue)#1 (3) {
+ ["flags":"SplPriorityQueue":private]=>
+ int(1)
+ ["isCorrupted":"SplPriorityQueue":private]=>
+ bool(false)
+ ["heap":"SplPriorityQueue":private]=>
+ array(4) {
+ [0]=>
+ array(2) {
+ ["data"]=>
+ string(1) "c"
+ ["priority"]=>
+ int(5)
+ }
+ [1]=>
+ array(2) {
+ ["data"]=>
+ string(1) "a"
+ ["priority"]=>
+ int(0)
+ }
+ [2]=>
+ array(2) {
+ ["data"]=>
+ string(1) "b"
+ ["priority"]=>
+ int(1)
+ }
+ [3]=>
+ array(2) {
+ ["data"]=>
+ string(1) "d"
+ ["priority"]=>
+ int(-2)
+ }
+ }
+}
+===DONE===
diff --git a/ext/spl/tests/pqueue_compare_basic.phpt b/ext/spl/tests/pqueue_compare_basic.phpt
new file mode 100644
index 0000000..1544add
--- /dev/null
+++ b/ext/spl/tests/pqueue_compare_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplPriorityQueue: test compare
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplPriorityQueue();
+var_dump($h->compare(4, 5) < 0);
+var_dump($h->compare(5, 5) == 0);
+var_dump($h->compare(5, 4) > 0);
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/pqueue_compare_error.phpt b/ext/spl/tests/pqueue_compare_error.phpt
new file mode 100644
index 0000000..610be2a
--- /dev/null
+++ b/ext/spl/tests/pqueue_compare_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: Priority queue compare, illegal number of args
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplPriorityQueue();
+$h->compare();
+$h->compare(1);
+$h->compare(1, 2, 3);
+?>
+--EXPECTF--
+Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 0 given in %s
+
+Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 1 given in %s
+
+Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 3 given in %s
+
diff --git a/ext/spl/tests/pqueue_current_error.phpt b/ext/spl/tests/pqueue_current_error.phpt
new file mode 100644
index 0000000..7fdf0af
--- /dev/null
+++ b/ext/spl/tests/pqueue_current_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplPriorityQueue current on empty queue should give null
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplPriorityQueue();
+var_dump($h->current());
+?>
+--EXPECT--
+NULL
diff --git a/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt
new file mode 100644
index 0000000..f543072
--- /dev/null
+++ b/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in beginchildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(array(1,2),2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function beginchildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt2->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->beginchildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt
new file mode 100644
index 0000000..88f03fb
--- /dev/null
+++ b/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in callHasChildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(1,2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function callHasChildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt2->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->callHasChildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt
new file mode 100644
index 0000000..e25d3ed
--- /dev/null
+++ b/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in endchildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(array(1,2));
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function endchildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+foreach ($recItIt as $val) echo "$val\n";
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+echo "===NEXT LOOP===\n";
+
+foreach ($recItIt2 as $val) echo "$val\n";
+
+?>
+--EXPECTF--
+1
+2
+===NEXT LOOP===
+1
+2
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->endchildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt b/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt
new file mode 100644
index 0000000..3a91ed5
--- /dev/null
+++ b/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in nextelement which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(1,2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function nextelement() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->nextelement()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursive_tree_iterator_001.phpt b/ext/spl/tests/recursive_tree_iterator_001.phpt
new file mode 100644
index 0000000..f70186c
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_001.phpt
@@ -0,0 +1,102 @@
+--TEST--
+SPL: RecursiveTreeIterator
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(
+ 0 => array(
+ "a",
+ 1,
+ ),
+ "a" => array(
+ 2,
+ "b",
+ 3 => array(
+ 4,
+ "c",
+ ),
+ "3" => array(
+ 4,
+ "c",
+ ),
+ ),
+);
+
+$it = new RecursiveArrayIterator($ary);
+echo "-- flags = BYPASS_KEY --\n";
+foreach(new RecursiveTreeIterator($it) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = BYPASS_CURRENT --\n";
+foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n";
+foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = 0 --\n";
+foreach(new RecursiveTreeIterator($it, 0) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n";
+foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+-- flags = BYPASS_KEY --
+[0] => |-Array
+[0] => | |-a
+[1] => | \-1
+[a] => \-Array
+[0] => |-2
+[1] => |-b
+[3] => \-Array
+[0] => |-4
+[1] => \-c
+-- flags = BYPASS_CURRENT --
+[|-0] => Array
+[| |-0] => a
+[| \-1] => 1
+[\-a] => Array
+[ |-0] => 2
+[ |-1] => b
+[ \-3] => Array
+[ |-0] => 4
+[ \-1] => c
+-- flags = BYPASS_KEY|BYPASS_KEY --
+[0] => Array
+[0] => a
+[1] => 1
+[a] => Array
+[0] => 2
+[1] => b
+[3] => Array
+[0] => 4
+[1] => c
+-- flags = 0 --
+[|-0] => |-Array
+[| |-0] => | |-a
+[| \-1] => | \-1
+[\-a] => \-Array
+[ |-0] => |-2
+[ |-1] => |-b
+[ \-3] => \-Array
+[ |-0] => |-4
+[ \-1] => \-c
+-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --
+[|-0] => |-Array
+[| |-0] => | |-a
+[| \-1] => | \-1
+[\-a] => \-Array
+[ |-0] => |-2
+[ |-1] => |-b
+[ \-3] => \-Array
+[ |-0] => |-4
+[ \-1] => \-c
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_002.phpt b/ext/spl/tests/recursive_tree_iterator_002.phpt
new file mode 100644
index 0000000..1aae288
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_002.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: RecursiveTreeIterator(void)
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+try {
+ new RecursiveTreeIterator();
+} catch (InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown\n";
+}
+?>
+===DONE===
+--EXPECTF--
+InvalidArgumentException thrown
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_003.phpt b/ext/spl/tests/recursive_tree_iterator_003.phpt
new file mode 100644
index 0000000..83c8553
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_003.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: RecursiveTreeIterator(non-traversable)
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+try {
+ new RecursiveTreeIterator(new ArrayIterator(array()));
+} catch (InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown\n";
+}
+?>
+===DONE===
+--EXPECTF--
+InvalidArgumentException thrown
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_004.phpt b/ext/spl/tests/recursive_tree_iterator_004.phpt
new file mode 100644
index 0000000..ad3ba6c
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_004.phpt
@@ -0,0 +1,43 @@
+--TEST--
+SPL: RecursiveTreeIterator methods
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(
+ 0 => array(
+ "a",
+ 1,
+ ),
+ "a" => array(
+ 2,
+ "b",
+ 3 => array(
+ 4,
+ "c",
+ ),
+ "3" => array(
+ 4,
+ "c",
+ ),
+ ),
+);
+
+$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary));
+foreach($it as $k => $v) {
+ echo '[' . $it->key() . '] => ' . $it->getPrefix() . $it->getEntry() . $it->getPostfix() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+[0] => |-Array
+[0] => | |-a
+[1] => | \-1
+[a] => \-Array
+[0] => |-2
+[1] => |-b
+[3] => \-Array
+[0] => |-4
+[1] => \-c
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_005.phpt b/ext/spl/tests/recursive_tree_iterator_005.phpt
new file mode 100644
index 0000000..b14811f
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_005.phpt
@@ -0,0 +1,116 @@
+--TEST--
+SPL: RecursiveTreeIterator and binary vs unicode (PHP 6.0+)
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(
+ 0 => array(
+ (binary) "binary",
+ "abc2",
+ 1,
+ ),
+ (binary) "binary" => array(
+ 2,
+ "b",
+ 3 => array(
+ 4,
+ "c",
+ ),
+ "4abc" => array(
+ 4,
+ "c",
+ ),
+ ),
+);
+
+$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary), 0);
+foreach($it as $k => $v) {
+ var_dump($v);
+}
+echo "\n----------------\n\n";
+foreach($it as $k => $v) {
+ var_dump($k);
+}
+echo "\n----------------\n\n";
+echo "key, getEntry, current:\n";
+foreach($it as $k => $v) {
+ var_dump($it->key(), $it->getEntry(), $it->current());
+}
+?>
+===DONE===
+--EXPECT--
+string(7) "|-Array"
+string(10) "| |-binary"
+string(8) "| |-abc2"
+string(5) "| \-1"
+string(7) "\-Array"
+string(5) " |-2"
+string(5) " |-b"
+string(9) " |-Array"
+string(7) " | |-4"
+string(7) " | \-c"
+string(9) " \-Array"
+string(7) " |-4"
+string(7) " \-c"
+
+----------------
+
+string(3) "|-0"
+string(5) "| |-0"
+string(5) "| |-1"
+string(5) "| \-2"
+string(8) "\-binary"
+string(5) " |-0"
+string(5) " |-1"
+string(5) " |-3"
+string(7) " | |-0"
+string(7) " | \-1"
+string(8) " \-4abc"
+string(7) " |-0"
+string(7) " \-1"
+
+----------------
+
+key, getEntry, current:
+string(3) "|-0"
+string(5) "Array"
+string(7) "|-Array"
+string(5) "| |-0"
+string(6) "binary"
+string(10) "| |-binary"
+string(5) "| |-1"
+string(4) "abc2"
+string(8) "| |-abc2"
+string(5) "| \-2"
+string(1) "1"
+string(5) "| \-1"
+string(8) "\-binary"
+string(5) "Array"
+string(7) "\-Array"
+string(5) " |-0"
+string(1) "2"
+string(5) " |-2"
+string(5) " |-1"
+string(1) "b"
+string(5) " |-b"
+string(5) " |-3"
+string(5) "Array"
+string(9) " |-Array"
+string(7) " | |-0"
+string(1) "4"
+string(7) " | |-4"
+string(7) " | \-1"
+string(1) "c"
+string(7) " | \-c"
+string(8) " \-4abc"
+string(5) "Array"
+string(9) " \-Array"
+string(7) " |-0"
+string(1) "4"
+string(7) " |-4"
+string(7) " \-1"
+string(1) "c"
+string(7) " \-c"
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_006.phpt b/ext/spl/tests/recursive_tree_iterator_006.phpt
new file mode 100644
index 0000000..17f51b6
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_006.phpt
@@ -0,0 +1,112 @@
+--TEST--
+SPL: RecursiveTreeIterator and IteratorAggregate
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(
+ 0 => array(
+ "a",
+ 1,
+ ),
+ "a" => array(
+ 2,
+ "b",
+ 3 => array(
+ 4,
+ "c",
+ ),
+ "3" => array(
+ 4,
+ "c",
+ ),
+ ),
+);
+
+class RecursiveArrayIteratorAggregated implements IteratorAggregate {
+ public $it;
+ function __construct($it) {
+ $this->it = new RecursiveArrayIterator($it);
+ }
+ function getIterator() {
+ return $this->it;
+ }
+}
+
+$it = new RecursiveArrayIteratorAggregated($ary);
+echo "-- flags = BYPASS_KEY --\n";
+foreach(new RecursiveTreeIterator($it) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = BYPASS_CURRENT --\n";
+foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n";
+foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = 0 --\n";
+foreach(new RecursiveTreeIterator($it, 0) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n";
+foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as $k => $v) {
+ echo "[$k] => $v\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+-- flags = BYPASS_KEY --
+[0] => |-Array
+[0] => | |-a
+[1] => | \-1
+[a] => \-Array
+[0] => |-2
+[1] => |-b
+[3] => \-Array
+[0] => |-4
+[1] => \-c
+-- flags = BYPASS_CURRENT --
+[|-0] => Array
+[| |-0] => a
+[| \-1] => 1
+[\-a] => Array
+[ |-0] => 2
+[ |-1] => b
+[ \-3] => Array
+[ |-0] => 4
+[ \-1] => c
+-- flags = BYPASS_KEY|BYPASS_KEY --
+[0] => Array
+[0] => a
+[1] => 1
+[a] => Array
+[0] => 2
+[1] => b
+[3] => Array
+[0] => 4
+[1] => c
+-- flags = 0 --
+[|-0] => |-Array
+[| |-0] => | |-a
+[| \-1] => | \-1
+[\-a] => \-Array
+[ |-0] => |-2
+[ |-1] => |-b
+[ \-3] => \-Array
+[ |-0] => |-4
+[ \-1] => \-c
+-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --
+[|-0] => |-Array
+[| |-0] => | |-a
+[| \-1] => | \-1
+[\-a] => \-Array
+[ |-0] => |-2
+[ |-1] => |-b
+[ \-3] => \-Array
+[ |-0] => |-4
+[ \-1] => \-c
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_007.phpt b/ext/spl/tests/recursive_tree_iterator_007.phpt
new file mode 100644
index 0000000..6a8ff84
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_007.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: RecursiveTreeIterator and Exception from getEntry()
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(new stdClass);
+
+class RecursiveArrayIteratorAggregated implements IteratorAggregate {
+ public $it;
+ function __construct($it) {
+ $this->it = new RecursiveArrayIterator($it);
+ }
+ function getIterator() {
+ return $this->it;
+ }
+}
+
+$it = new RecursiveArrayIteratorAggregated($ary);
+try {
+ foreach(new RecursiveTreeIterator($it) as $k => $v) {
+ echo "[$k] => $v\n";
+ }
+} catch (UnexpectedValueException $e) {
+ echo "UnexpectedValueException thrown\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+UnexpectedValueException thrown
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_008.phpt b/ext/spl/tests/recursive_tree_iterator_008.phpt
new file mode 100644
index 0000000..a034980
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_008.phpt
@@ -0,0 +1,41 @@
+--TEST--
+SPL: RecursiveTreeIterator::setPrefixPart()
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+
+$ary = array(
+ "a" => array("b"),
+ "c" => array("d"),
+);
+
+$it = new RecursiveArrayIterator($ary);
+$it = new RecursiveTreeIterator($it);
+for($i = 0; $i < 6; ++$i) {
+ $it->setPrefixPart($i, $i);
+}
+foreach($it as $k => $v) {
+ echo "[$k] => $v\n";
+}
+try {
+ $it->setPrefixPart(-1, "");
+ $it->setPrefixPart(6, "");
+} catch (OutOfRangeException $e) {
+ echo "OutOfRangeException thrown\n";
+}
+try {
+ $it->setPrefixPart(6, "");
+} catch (OutOfRangeException $e) {
+ echo "OutOfRangeException thrown\n";
+}
+?>
+===DONE===
+--EXPECTF--
+[a] => 035Array
+[0] => 0145b
+[c] => 045Array
+[0] => 0245d
+OutOfRangeException thrown
+OutOfRangeException thrown
+===DONE===
diff --git a/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt b/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt
new file mode 100644
index 0000000..81c853f
--- /dev/null
+++ b/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RecursiveTreeIterator::setPrefixPart() Test arguments
+--CREDITS--
+Roshan Abraham (roshanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+
+$arr = array(
+ "a" => array("b")
+);
+
+$it = new RecursiveArrayIterator($arr);
+$it = new RecursiveTreeIterator($it);
+
+$it->setPrefixPart(1); // Should throw a warning as setPrefixPart expects 2 arguments
+
+$a = new stdClass();
+$it->setPrefixPart($a, 1); // Should throw a warning as setPrefixPart expects argument 1 to be long integer
+
+$it->setPrefixPart(1, $a); // Should throw a warning as setPrefixPart expects argument 2 to be a string
+
+
+?>
+===DONE===
+--EXPECTF--
+Warning: RecursiveTreeIterator::setPrefixPart() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: RecursiveTreeIterator::setPrefixPart() expects parameter 1 to be long, object given in %s on line %d
+
+Warning: RecursiveTreeIterator::setPrefixPart() expects parameter 2 to be %binary_string_optional%, object given in %s on line %d
+===DONE===
diff --git a/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt
new file mode 100644
index 0000000..c9476e0
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RecursiveIteratorIterator::beginIteration() is called by RecursiveIteratorIterator::rewind()
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2);
+$sub_iterator = new RecursiveArrayIterator($sample_array);
+
+$iterator = new RecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+
+class SkipsFirstElementRecursiveIteratorIterator extends RecursiveIteratorIterator {
+ public function beginIteration() {
+ echo "::beginIteration() was invoked\n";
+ $this->next();
+ }
+}
+$iterator = new SkipsFirstElementRecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+?>
+--EXPECT--
+int(1)
+int(2)
+::beginIteration() was invoked
+int(2)
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt
new file mode 100644
index 0000000..0355401
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RecursiveIteratorIterator::endIteration() is called when ::valid() first returns false
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2);
+$sub_iterator = new RecursiveArrayIterator($sample_array);
+
+$iterator = new RecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+
+class EndIterationRecursiveIteratorIterator extends RecursiveIteratorIterator {
+ public function endIteration() {
+ echo "::endIteration() was invoked\n";
+ }
+}
+$iterator = new EndIterationRecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+?>
+--EXPECT--
+int(1)
+int(2)
+int(1)
+int(2)
+::endIteration() was invoked
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt
new file mode 100644
index 0000000..5d1c958
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: RecursiveIteratorIterator::getSubIterator() returns iterator passed in constructor
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2, array(3, 4));
+
+$sub_iterator = new RecursiveArrayIterator($sample_array);
+$not_sub_iterator = new RecursiveArrayIterator($sample_array);
+$iterator = new RecursiveIteratorIterator($sub_iterator);
+
+var_dump($iterator->getSubIterator() === $sub_iterator);
+var_dump($iterator->getSubIterator() === $not_sub_iterator);
+?>
+--EXPECT--
+bool(true)
+bool(false)
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt
new file mode 100644
index 0000000..760082f
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: RecursiveIteratorIterator::getSubIterator() expects at most 1 parameter
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator(array()));
+$iterator->getSubIterator();
+$iterator->getSubIterator(0);
+$iterator->getSubIterator(0, 0);
+?>
+--EXPECTF--
+Warning: RecursiveIteratorIterator::getSubIterator() expects at most 1 parameter, 2 given in %s on line 5
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt
new file mode 100644
index 0000000..a7b84c4
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SPL: RecursiveIteratorIterator::getSubIterator() returns different iterators depending on the current element
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2, array(3, 4));
+
+$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array));
+
+$iterator->next();
+$iterator->next();
+var_dump(get_class($iterator->getSubIterator()));
+var_dump($iterator->getSubIterator()->getArrayCopy());
+$iterator->next();
+var_dump(get_class($iterator->getSubIterator()));
+var_dump($iterator->getSubIterator()->getArrayCopy());
+?>
+--EXPECTF--
+%unicode|string%(22) "RecursiveArrayIterator"
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+ }
+}
+%unicode|string%(22) "RecursiveArrayIterator"
+array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+}
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt
new file mode 100644
index 0000000..aac4e65
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: RecursiveIteratorIterator::getSubIterator() returns NULL if there's no current element
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1);
+
+$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array));
+
+$iterator->next();
+var_dump(is_null($iterator->getSubIterator()));
+$iterator->next();
+var_dump(is_null($iterator->getSubIterator()));
+?>
+--EXPECT--
+bool(false)
+bool(false)
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt
new file mode 100644
index 0000000..ff18840
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SPL: RecursiveIteratorIterator::getSubIterator() with explicit level parameter
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2, array(3, 4));
+
+$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array));
+
+$iterator->next();
+$iterator->next();
+$iterator->next();
+var_dump($iterator->getSubIterator(-1));
+var_dump($iterator->getSubIterator(0)->getArrayCopy());
+var_dump($iterator->getSubIterator(1)->getArrayCopy());
+var_dump($iterator->getSubIterator(2));
+?>
+--EXPECT--
+NULL
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+ }
+}
+array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+}
+NULL
+
diff --git a/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt
new file mode 100644
index 0000000..0bf4f19
--- /dev/null
+++ b/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt
@@ -0,0 +1,39 @@
+--TEST--
+SPL: RecursiveIteratorIterator::nextElement() is called when the next element is ready
+--CREDITS--
+Matt Raines matt@raines.me.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$sample_array = array(1, 2, array(3, 4));
+$sub_iterator = new RecursiveArrayIterator($sample_array);
+
+$iterator = new RecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+
+class NextElementRecursiveIteratorIterator extends RecursiveIteratorIterator {
+ public function nextElement() {
+ echo "::nextElement() was invoked\n";
+ }
+}
+$iterator = new NextElementRecursiveIteratorIterator($sub_iterator);
+foreach ($iterator as $element) {
+ var_dump($element);
+}
+?>
+--EXPECT--
+int(1)
+int(2)
+int(3)
+int(4)
+::nextElement() was invoked
+int(1)
+::nextElement() was invoked
+int(2)
+::nextElement() was invoked
+int(3)
+::nextElement() was invoked
+int(4)
+
diff --git a/ext/spl/tests/regexIterator_flags_basic.phpt b/ext/spl/tests/regexIterator_flags_basic.phpt
new file mode 100644
index 0000000..535be00
--- /dev/null
+++ b/ext/spl/tests/regexIterator_flags_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: RegexIterator::getFlags() and setFlags() basic tests
+--CREDITS--
+Felix De Vliegher <felix.devliegher@gmail.com>
+--FILE--
+<?php
+
+$array = array('foo', 'bar', 'baz');
+$iterator = new ArrayIterator($array);
+$regexIterator = new RegexIterator($iterator, "/f/", null, RegexIterator::USE_KEY);
+
+var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY);
+
+// Test a change in flags, there's only one class constant so it has to be another int value
+$regexIterator->setFlags(3);
+var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY);
+$regexIterator->setFlags(RegexIterator::USE_KEY);
+var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY);
+
+?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
diff --git a/ext/spl/tests/regexIterator_mode_basic.phpt b/ext/spl/tests/regexIterator_mode_basic.phpt
new file mode 100644
index 0000000..a39b969
--- /dev/null
+++ b/ext/spl/tests/regexIterator_mode_basic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+SPL: RegexIterator::getMode() and setMode() basic tests
+--CREDITS--
+Felix De Vliegher <felix.devliegher@gmail.com>
+--FILE--
+<?php
+
+$array = array('foo', 'bar', 'baz');
+$iterator = new ArrayIterator($array);
+$regexIterator = new RegexIterator($iterator, "/f/");
+
+var_dump($regexIterator->getMode() === RegexIterator::MATCH);
+
+$regexIterator->setMode(RegexIterator::MATCH);
+var_dump($regexIterator->getMode() === RegexIterator::MATCH);
+
+$regexIterator->setMode(RegexIterator::GET_MATCH);
+var_dump($regexIterator->getMode() === RegexIterator::GET_MATCH);
+
+$regexIterator->setMode(RegexIterator::ALL_MATCHES);
+var_dump($regexIterator->getMode() === RegexIterator::ALL_MATCHES);
+
+$regexIterator->setMode(RegexIterator::SPLIT);
+var_dump($regexIterator->getMode() === RegexIterator::SPLIT);
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/spl/tests/regexIterator_setMode_error.phpt b/ext/spl/tests/regexIterator_setMode_error.phpt
new file mode 100644
index 0000000..52af499
--- /dev/null
+++ b/ext/spl/tests/regexIterator_setMode_error.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: RegexIterator::setMode() error tests
+--CREDITS--
+Felix De Vliegher <felix.devliegher@gmail.com>
+--FILE--
+<?php
+
+$array = array('foo', 'bar', 'baz');
+$regexIterator = new RegexIterator(new ArrayIterator($array), "/f/");
+
+var_dump($regexIterator->getMode());
+
+try {
+ $regexIterator->setMode(7);
+} catch (InvalidArgumentException $e) {
+ var_dump($e->getMessage());
+ var_dump($e->getCode());
+}
+
+$regexIterator->setMode('foo');
+
+?>
+--EXPECTF--
+int(0)
+string(14) "Illegal mode 7"
+int(0)
+
+Warning: RegexIterator::setMode() expects parameter 1 to be long, string given in %s on line %d
diff --git a/ext/spl/tests/regexiterator_getpregflags.phpt b/ext/spl/tests/regexiterator_getpregflags.phpt
new file mode 100644
index 0000000..58a4dc4
--- /dev/null
+++ b/ext/spl/tests/regexiterator_getpregflags.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: RegexIterator::getPregFlags()
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class myIterator implements Iterator {
+
+function current (){}
+function key ( ){}
+function next ( ){}
+function rewind ( ){}
+function valid ( ){}
+
+
+}
+
+class TestRegexIterator extends RegexIterator{}
+
+$rege = '/^a/';
+
+
+$r = new TestRegexIterator(new myIterator, $rege);
+
+$r->setPregFlags(PREG_OFFSET_CAPTURE);
+
+echo is_long($r->getPregFlags());
+
+?>
+--EXPECTF--
+1 \ No newline at end of file
diff --git a/ext/spl/tests/regexiterator_getregex.phpt b/ext/spl/tests/regexiterator_getregex.phpt
new file mode 100644
index 0000000..d3113a5
--- /dev/null
+++ b/ext/spl/tests/regexiterator_getregex.phpt
@@ -0,0 +1,29 @@
+--TEST--
+SPL: RegexIterator::getRegex() basic tests
+--CREDITS--
+Joshua Thijssen <jthijssen@noxlogic.nl>
+--FILE--
+<?php
+
+$array = array('cat', 'hat', 'sat');
+$iterator = new ArrayIterator($array);
+
+# Simple regex
+$regexIterator = new RegexIterator($iterator, '/.at/');
+var_dump($regexIterator->getRegex());
+
+# Empty regular expression
+$regexIterator = new RegexIterator($iterator, '//');
+var_dump($regexIterator->getRegex());
+
+# "Complex" email regular expression
+$regexIterator = new RegexIterator($iterator, '|\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b|');
+var_dump($regexIterator->getRegex());
+
+
+
+?>
+--EXPECT--
+string(5) "/.at/"
+string(2) "//"
+string(43) "|\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b|"
diff --git a/ext/spl/tests/regexiterator_setflags_exception.phpt b/ext/spl/tests/regexiterator_setflags_exception.phpt
new file mode 100644
index 0000000..fdc8bca
--- /dev/null
+++ b/ext/spl/tests/regexiterator_setflags_exception.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SPL: RegexIterator::setFlags() exceptions test
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class myIterator implements Iterator {
+
+function current (){}
+function key ( ){}
+function next ( ){}
+function rewind ( ){}
+function valid ( ){}
+
+
+}
+
+class TestRegexIterator extends RegexIterator{}
+
+$rege = '/^a/';
+
+
+$r = new TestRegexIterator(new myIterator, $rege);
+
+try{
+ $r->setFlags();
+}catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECTF--
+Warning: RegexIterator::setFlags() expects exactly 1 parameter, 0 given in %s \ No newline at end of file
diff --git a/ext/spl/tests/regexiterator_setpregflags.phpt b/ext/spl/tests/regexiterator_setpregflags.phpt
new file mode 100644
index 0000000..ea1b455
--- /dev/null
+++ b/ext/spl/tests/regexiterator_setpregflags.phpt
@@ -0,0 +1,34 @@
+--TEST--
+SPL: RegexIterator::setPregFlags()
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class myIterator implements Iterator {
+
+function current (){}
+function key ( ){}
+function next ( ){}
+function rewind ( ){}
+function valid ( ){}
+
+
+}
+
+class TestRegexIterator extends RegexIterator{}
+
+$rege = '/^a/';
+
+
+$r = new TestRegexIterator(new myIterator, $rege);
+
+$r->setPregFlags(PREG_OFFSET_CAPTURE);
+
+echo $r->getPregFlags();
+
+
+?>
+--EXPECTF--
+256 \ No newline at end of file
diff --git a/ext/spl/tests/regexiterator_setpregflags_exception.phpt b/ext/spl/tests/regexiterator_setpregflags_exception.phpt
new file mode 100644
index 0000000..cc7c17c
--- /dev/null
+++ b/ext/spl/tests/regexiterator_setpregflags_exception.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SPL: RegexIterator::getPregFlags() exception test
+--CREDITS--
+Lance Kesson jac_kesson@hotmail.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class myIterator implements Iterator {
+
+function current (){}
+function key ( ){}
+function next ( ){}
+function rewind ( ){}
+function valid ( ){}
+
+
+}
+
+class TestRegexIterator extends RegexIterator{}
+
+$rege = '/^a/';
+
+
+$r = new TestRegexIterator(new myIterator, $rege);
+
+
+try{
+ $r->setPregFlags();
+}catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECTF--
+Warning: RegexIterator::setPregFlags() expects exactly 1 parameter, 0 given in %s \ No newline at end of file
diff --git a/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt b/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt
new file mode 100644
index 0000000..cd4ea5b
--- /dev/null
+++ b/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Checks that the shift() method of DoublyLinkedList does not accept args.
+--CREDITS--
+PHPNW Test Fest 2009 - Rick Ogden
+--FILE--
+<?php
+$ll = new SplDoublyLinkedList();
+$ll->push(1);
+$ll->push(2);
+
+var_dump($ll->shift(1));
+?>
+--EXPECTF--
+Warning: SplDoublyLinkedList::shift() expects exactly 0 parameters, 1 given in %s on line %d
+NULL
diff --git a/ext/spl/tests/spl_001.phpt b/ext/spl/tests/spl_001.phpt
new file mode 100644
index 0000000..e101272
--- /dev/null
+++ b/ext/spl/tests/spl_001.phpt
@@ -0,0 +1,34 @@
+--TEST--
+SPL: iterator_to_array() and iterator_count()
+--FILE--
+<?php
+
+$it = new ArrayObject(array("x"=>1, 1=>2, 3=>3, 4, "1"=>5));
+
+$ar = iterator_to_array($it);
+
+var_dump(iterator_count($it));
+
+print_r($ar);
+
+foreach($ar as $v)
+{
+ var_dump($v);
+}
+
+?>
+===DONE===
+--EXPECT--
+int(4)
+Array
+(
+ [x] => 1
+ [1] => 5
+ [3] => 3
+ [4] => 4
+)
+int(1)
+int(5)
+int(3)
+int(4)
+===DONE===
diff --git a/ext/spl/tests/spl_002.phpt b/ext/spl/tests/spl_002.phpt
new file mode 100644
index 0000000..d8b71b2
--- /dev/null
+++ b/ext/spl/tests/spl_002.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: Countable
+--FILE--
+<?php
+
+class Test implements Countable
+{
+ function count()
+ {
+ return 4;
+ }
+};
+
+$a = new Test;
+
+var_dump(count($a));
+
+?>
+===DONE===
+--EXPECT--
+int(4)
+===DONE===
diff --git a/ext/spl/tests/spl_003.phpt b/ext/spl/tests/spl_003.phpt
new file mode 100644
index 0000000..e92a41a
--- /dev/null
+++ b/ext/spl/tests/spl_003.phpt
@@ -0,0 +1,74 @@
+--TEST--
+SPL: class_parents() and class_implements()
+--FILE--
+<?php
+class a{}
+class b extends a{}
+class c extends b{}
+class d{}
+var_dump(class_parents(new c),
+ class_parents("c"),
+ class_parents(new b),
+ class_parents("b"),
+ class_parents("d"),
+ class_parents("foo", 0),
+ class_parents("foo", 1)
+);
+
+interface iface1{}
+interface iface2{}
+class f implements iface1, iface2{}
+var_dump(class_implements(new a),
+ class_implements("a"),
+ class_implements("aaa"),
+ class_implements("bbb", 0)
+);
+
+function __autoload($cname) {
+ var_dump($cname);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Warning: class_parents(): Class foo does not exist in %sspl_003.php on line %d
+string(3) "foo"
+
+Warning: class_parents(): Class foo does not exist and could not be loaded in %sspl_003.php on line %d
+array(2) {
+ ["b"]=>
+ string(1) "b"
+ ["a"]=>
+ string(1) "a"
+}
+array(2) {
+ ["b"]=>
+ string(1) "b"
+ ["a"]=>
+ string(1) "a"
+}
+array(1) {
+ ["a"]=>
+ string(1) "a"
+}
+array(1) {
+ ["a"]=>
+ string(1) "a"
+}
+array(0) {
+}
+bool(false)
+bool(false)
+string(3) "aaa"
+
+Warning: class_implements(): Class aaa does not exist and could not be loaded in %sspl_003.php on line %d
+
+Warning: class_implements(): Class bbb does not exist in %sspl_003.php on line %d
+array(0) {
+}
+array(0) {
+}
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/spl_004.phpt b/ext/spl/tests/spl_004.phpt
new file mode 100644
index 0000000..97896f8
--- /dev/null
+++ b/ext/spl/tests/spl_004.phpt
@@ -0,0 +1,84 @@
+--TEST--
+SPL: iterator_apply()
+--FILE--
+<?php
+
+function my_error_handler($errno, $errstr, $errfile, $errline) {
+ echo "Error: $errstr\n";
+}
+
+set_error_handler('my_error_handler');
+
+function test_arg($arg)
+{
+ if ($arg instanceof Iterator)
+ {
+ var_dump($arg->key());
+ var_dump($arg->current());
+ }
+ else
+ {
+ var_dump($arg);
+ }
+ return true;
+}
+
+function test()
+{
+ static $arg = 0;
+ var_dump($arg++);
+ return true;
+}
+
+$it = new RecursiveArrayIterator(array(1, array(21, 22), 3));
+
+var_dump(iterator_apply($it, 'test', NULL));
+
+echo "===ARGS===\n";
+var_dump(iterator_apply($it, 'test_arg', array($it)));
+
+echo "===RECURSIVE===\n";
+$it = new RecursiveIteratorIterator($it);
+var_dump(iterator_apply($it, 'test'));
+
+echo "===ERRORS===\n";
+var_dump(iterator_apply($it, 'test', 1));
+var_dump(iterator_apply($it, 'non_existing_functon'));
+var_dump(iterator_apply($it, 'non_existing_functon', NULL, 2));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+int(0)
+int(1)
+int(2)
+int(3)
+===ARGS===
+int(0)
+int(1)
+int(1)
+array(2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+}
+int(2)
+int(3)
+int(3)
+===RECURSIVE===
+int(3)
+int(4)
+int(5)
+int(6)
+int(4)
+===ERRORS===
+Error: Argument 3 passed to iterator_apply() must be of the type array, integer given
+Error: iterator_apply() expects parameter 3 to be array, integer given
+NULL
+Error: iterator_apply() expects parameter 2 to be a valid callback, function 'non_existing_functon' not found or invalid function name
+NULL
+Error: iterator_apply() expects at most 3 parameters, 4 given
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_005.phpt b/ext/spl/tests/spl_005.phpt
new file mode 100644
index 0000000..219c791
--- /dev/null
+++ b/ext/spl/tests/spl_005.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: spl_object_hash()
+--FILE--
+<?php
+
+var_dump(spl_object_hash(new stdClass));
+var_dump(spl_object_hash(42));
+var_dump(spl_object_hash());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(32) "%s"
+
+Warning: spl_object_hash() expects parameter 1 to be object, integer given in %sspl_005.php on line %d
+NULL
+
+Warning: spl_object_hash() expects exactly 1 parameter, 0 given in %sspl_005.php on line %d
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_006.phpt b/ext/spl/tests/spl_006.phpt
new file mode 100644
index 0000000..1f5f85f
--- /dev/null
+++ b/ext/spl/tests/spl_006.phpt
@@ -0,0 +1,39 @@
+--TEST--
+SPL: iterator_to_array() without keys
+--FILE--
+<?php
+
+$it = new AppendIterator();
+$it->append(new ArrayIterator(array(1,2)));
+$it->append(new ArrayIterator(array(2,3)));
+
+var_dump(iterator_to_array($it));
+var_dump(iterator_to_array($it, false));
+var_dump(iterator_to_array($it, true));
+
+?>
+===DONE===
+--EXPECT--
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(3)
+}
+array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+}
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(3)
+}
+===DONE===
diff --git a/ext/spl/tests/spl_007.phpt b/ext/spl/tests/spl_007.phpt
new file mode 100644
index 0000000..6d4059d
--- /dev/null
+++ b/ext/spl/tests/spl_007.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: iterator_apply() with callback using __call()
+--FILE--
+<?php
+
+class Foo {
+ public function __call($name, $params) {
+ echo "Called $name.\n";
+ return true;
+ }
+}
+
+$it = new ArrayIterator(array(1, 2, 3));
+
+iterator_apply($it, array(new Foo, "foobar"));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+Called foobar.
+Called foobar.
+Called foobar.
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_001.phpt b/ext/spl/tests/spl_autoload_001.phpt
new file mode 100644
index 0000000..ff9d1e9
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_001.phpt
@@ -0,0 +1,136 @@
+--TEST--
+SPL: spl_autoload() and friends
+--INI--
+include_path=.
+--FILE--
+<?php
+
+echo "===EMPTY===\n";
+
+var_dump(spl_autoload_extensions());
+
+try
+{
+ spl_autoload("TestClass");
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+$test_exts = array(NULL, "1", ".inc,,.php.inc", "");
+
+foreach($test_exts as $exts)
+{
+ echo "===($exts)===\n";
+ try
+ {
+ spl_autoload("TestClass", $exts);
+ }
+ catch(Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ }
+}
+
+try
+{
+ spl_autoload_extensions(".inc,.php.inc");
+ spl_autoload("TestClass");
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+function TestFunc1($classname)
+{
+ echo __METHOD__ . "($classname)\n";
+}
+
+function TestFunc2($classname)
+{
+ echo __METHOD__ . "($classname)\n";
+}
+
+echo "===SPL_AUTOLOAD()===\n";
+
+spl_autoload_register();
+
+try
+{
+ var_dump(spl_autoload_extensions(".inc"));
+ var_dump(class_exists("TestClass", true));
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+echo "===REGISTER===\n";
+
+spl_autoload_unregister("spl_autoload");
+spl_autoload_register("TestFunc1");
+spl_autoload_register("TestFunc2");
+spl_autoload_register("TestFunc2"); /* 2nd call ignored */
+spl_autoload_extensions(".inc,.class.inc"); /* we do not have spl_autoload_registered yet */
+
+try
+{
+ var_dump(class_exists("TestClass", true));
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+echo "===LOAD===\n";
+
+spl_autoload_register("spl_autoload");
+var_dump(class_exists("TestClass", true));
+
+echo "===NOFUNCTION===\n";
+
+try
+{
+ spl_autoload_register("unavailable_autoload_function");
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===EMPTY===
+string(9) ".inc,.php"
+%stestclass.inc
+Exception: Class TestClass could not be loaded
+===()===
+Exception: Class TestClass could not be loaded
+===(1)===
+Exception: Class TestClass could not be loaded
+===(.inc,,.php.inc)===
+%stestclass
+%stestclass.php.inc
+Exception: Class TestClass could not be loaded
+===()===
+Exception: Class TestClass could not be loaded
+Exception: Class TestClass could not be loaded
+===SPL_AUTOLOAD()===
+string(4) ".inc"
+Exception: Class TestClass could not be loaded
+===REGISTER===
+TestFunc1(TestClass)
+TestFunc2(TestClass)
+bool(false)
+===LOAD===
+TestFunc1(TestClass)
+TestFunc2(TestClass)
+%stestclass.class.inc
+bool(true)
+===NOFUNCTION===
+Exception: Function 'unavailable_autoload_function' not found (function 'unavailable_autoload_function' not found or invalid function name)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_002.phpt b/ext/spl/tests/spl_autoload_002.phpt
new file mode 100644
index 0000000..2373d6d
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_002.phpt
@@ -0,0 +1,70 @@
+--TEST--
+SPL: spl_autoload_functions()
+--SKIPIF--
+<?php
+if (spl_autoload_functions() !== false) die('skip __autoload() registered by php.ini');
+?>
+--FILE--
+<?php
+
+function SplAutoloadTest1($name) {}
+function SplAutoloadTest2($name) {}
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_register();
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_register('SplAutoloadTest1');
+spl_autoload_register('SplAutoloadTest2');
+spl_autoload_register('SplAutoloadTest1');
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_unregister('SplAutoloadTest1');
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_unregister('spl_autoload_call');
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_register();
+
+var_dump(spl_autoload_functions());
+
+spl_autoload_unregister('spl_autoload');
+
+var_dump(spl_autoload_functions());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+bool(false)
+array(1) {
+ [0]=>
+ string(12) "spl_autoload"
+}
+array(3) {
+ [0]=>
+ string(12) "spl_autoload"
+ [1]=>
+ string(16) "SplAutoloadTest1"
+ [2]=>
+ string(16) "SplAutoloadTest2"
+}
+array(2) {
+ [0]=>
+ string(12) "spl_autoload"
+ [1]=>
+ string(16) "SplAutoloadTest2"
+}
+bool(false)
+array(1) {
+ [0]=>
+ string(12) "spl_autoload"
+}
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_003.phpt b/ext/spl/tests/spl_autoload_003.phpt
new file mode 100644
index 0000000..7c0bd1a
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_003.phpt
@@ -0,0 +1,45 @@
+--TEST--
+SPL: spl_autoload() and friends
+--INI--
+include_path=.
+--FILE--
+<?php
+
+function TestFunc1($classname)
+{
+ echo __METHOD__ . "($classname)\n";
+}
+
+function TestFunc2($classname)
+{
+ echo __METHOD__ . "($classname)\n";
+ throw new Exception("Class $classname missing");
+}
+
+function TestFunc3($classname)
+{
+ echo __METHOD__ . "($classname)\n";
+}
+
+spl_autoload_register("TestFunc1");
+spl_autoload_register("TestFunc2");
+spl_autoload_register("TestFunc3");
+
+try
+{
+ var_dump(class_exists("TestClass", true));
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+TestFunc1(TestClass)
+TestFunc2(TestClass)
+TestFunc3(TestClass)
+Exception: Class TestClass missing
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_004.phpt b/ext/spl/tests/spl_autoload_004.phpt
new file mode 100644
index 0000000..1f26521
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_004.phpt
@@ -0,0 +1,43 @@
+--TEST--
+SPL: spl_autoload() with static methods
+--INI--
+include_path=.
+--FILE--
+<?php
+
+class MyAutoLoader {
+
+ static function autoLoad($className) {
+ echo __METHOD__ . "($className)\n";
+ }
+}
+
+spl_autoload_register(array('MyAutoLoader', 'autoLoad'));
+
+// and
+
+$myAutoLoader = new MyAutoLoader();
+
+spl_autoload_register(array($myAutoLoader, 'autoLoad'));
+
+var_dump(spl_autoload_functions());
+
+// check
+var_dump(class_exists("TestClass", true));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "autoLoad"
+ }
+}
+MyAutoLoader::autoLoad(TestClass)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_005.phpt b/ext/spl/tests/spl_autoload_005.phpt
new file mode 100644
index 0000000..f4db521
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_005.phpt
@@ -0,0 +1,55 @@
+--TEST--
+SPL: spl_autoload() with methods
+--INI--
+include_path=.
+--FILE--
+<?php
+
+class MyAutoLoader {
+
+ function autoLoad($className)
+ {
+ echo __METHOD__ . "($className)\n";
+ }
+
+ function autoThrow($className)
+ {
+ echo __METHOD__ . "($className)\n";
+ throw new Exception("Unavailable");
+ }
+}
+
+try
+{
+ spl_autoload_register(array('MyAutoLoader', 'autoLoad'), true);
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+// and
+
+$myAutoLoader = new MyAutoLoader();
+
+spl_autoload_register(array($myAutoLoader, 'autoLoad'));
+spl_autoload_register(array($myAutoLoader, 'autoThrow'));
+
+try
+{
+ var_dump(class_exists("TestClass", true));
+}
+catch(Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: Passed array specifies a non static method but no object (non-static method MyAutoLoader::autoLoad() should not be called statically)
+MyAutoLoader::autoLoad(TestClass)
+MyAutoLoader::autoThrow(TestClass)
+Exception: Unavailable
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_006.phpt b/ext/spl/tests/spl_autoload_006.phpt
new file mode 100644
index 0000000..21a6084
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_006.phpt
@@ -0,0 +1,37 @@
+--TEST--
+SPL: spl_autoload() with static methods
+--INI--
+include_path=.
+--FILE--
+<?php
+
+class MyAutoLoader {
+
+ static function autoLoad($className) {
+ echo __METHOD__ . "($className)\n";
+ }
+}
+
+spl_autoload_register('MyAutoLoader::autoLoad');
+
+var_dump(spl_autoload_functions());
+
+// check
+var_dump(class_exists("TestClass", true));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "autoLoad"
+ }
+}
+MyAutoLoader::autoLoad(TestClass)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_007.phpt b/ext/spl/tests/spl_autoload_007.phpt
new file mode 100644
index 0000000..1a81f19
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_007.phpt
@@ -0,0 +1,138 @@
+--TEST--
+SPL: spl_autoload() with inaccessible methods
+--INI--
+include_path=.
+--FILE--
+<?php
+
+class MyAutoLoader {
+
+ static protected function noAccess($className) {
+ echo __METHOD__ . "($className)\n";
+ }
+
+ static function autoLoad($className) {
+ echo __METHOD__ . "($className)\n";
+ }
+
+ function dynaLoad($className) {
+ echo __METHOD__ . "($className)\n";
+ }
+}
+
+$obj = new MyAutoLoader;
+
+$funcs = array(
+ 'MyAutoLoader::notExist',
+ 'MyAutoLoader::noAccess',
+ 'MyAutoLoader::autoLoad',
+ 'MyAutoLoader::dynaLoad',
+ array('MyAutoLoader', 'notExist'),
+ array('MyAutoLoader', 'noAccess'),
+ array('MyAutoLoader', 'autoLoad'),
+ array('MyAutoLoader', 'dynaLoad'),
+ array($obj, 'notExist'),
+ array($obj, 'noAccess'),
+ array($obj, 'autoLoad'),
+ array($obj, 'dynaLoad'),
+);
+
+foreach($funcs as $idx => $func)
+{
+ if ($idx) echo "\n";
+ try
+ {
+ var_dump($func);
+ spl_autoload_register($func);
+ echo "ok\n";
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(22) "MyAutoLoader::notExist"
+Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notExist')
+
+string(22) "MyAutoLoader::noAccess"
+Function 'MyAutoLoader::noAccess' not callable (cannot access protected method MyAutoLoader::noAccess())
+
+string(22) "MyAutoLoader::autoLoad"
+ok
+
+string(22) "MyAutoLoader::dynaLoad"
+Function 'MyAutoLoader::dynaLoad' not callable (non-static method MyAutoLoader::dynaLoad() should not be called statically)
+
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "notExist"
+}
+Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notExist')
+
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "noAccess"
+}
+Passed array does not specify a callable static method (cannot access protected method MyAutoLoader::noAccess())
+
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "autoLoad"
+}
+ok
+
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "dynaLoad"
+}
+Passed array specifies a non static method but no object (non-static method MyAutoLoader::dynaLoad() should not be called statically)
+
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "notExist"
+}
+Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notExist')
+
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "noAccess"
+}
+Passed array does not specify a callable method (cannot access protected method MyAutoLoader::noAccess())
+
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "autoLoad"
+}
+ok
+
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "dynaLoad"
+}
+ok
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_008.phpt b/ext/spl/tests/spl_autoload_008.phpt
new file mode 100644
index 0000000..4b10351
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_008.phpt
@@ -0,0 +1,129 @@
+--TEST--
+SPL: spl_autoload() with exceptions
+--INI--
+include_path=.
+--FILE--
+<?php
+
+function MyAutoLoad($className)
+{
+ echo __METHOD__ . "($className)\n";
+ throw new Exception('Bla');
+}
+
+class MyAutoLoader
+{
+ static function autoLoad($className)
+ {
+ echo __METHOD__ . "($className)\n";
+ throw new Exception('Bla');
+ }
+
+ function dynaLoad($className)
+ {
+ echo __METHOD__ . "($className)\n";
+ throw new Exception('Bla');
+ }
+}
+
+$obj = new MyAutoLoader;
+
+$funcs = array(
+ 'MyAutoLoad',
+ 'MyAutoLoader::autoLoad',
+ 'MyAutoLoader::dynaLoad',
+ array('MyAutoLoader', 'autoLoad'),
+ array('MyAutoLoader', 'dynaLoad'),
+ array($obj, 'autoLoad'),
+ array($obj, 'dynaLoad'),
+);
+
+foreach($funcs as $idx => $func)
+{
+ echo "====$idx====\n";
+
+ try
+ {
+ var_dump($func);
+ spl_autoload_register($func);
+ if (count(spl_autoload_functions()))
+ {
+ echo "registered\n";
+
+ var_dump(class_exists("NoExistingTestClass", true));
+ }
+ }
+ catch (Exception $e)
+ {
+ echo get_class($e) . ": " . $e->getMessage() . "\n";
+ }
+
+ spl_autoload_unregister($func);
+ var_dump(count(spl_autoload_functions()));
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+====0====
+string(10) "MyAutoLoad"
+registered
+MyAutoLoad(NoExistingTestClass)
+Exception: Bla
+int(0)
+====1====
+string(22) "MyAutoLoader::autoLoad"
+registered
+MyAutoLoader::autoLoad(NoExistingTestClass)
+Exception: Bla
+int(0)
+====2====
+string(22) "MyAutoLoader::dynaLoad"
+LogicException: Function 'MyAutoLoader::dynaLoad' not callable (non-static method MyAutoLoader::dynaLoad() should not be called statically)
+int(0)
+====3====
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "autoLoad"
+}
+registered
+MyAutoLoader::autoLoad(NoExistingTestClass)
+Exception: Bla
+int(0)
+====4====
+array(2) {
+ [0]=>
+ string(12) "MyAutoLoader"
+ [1]=>
+ string(8) "dynaLoad"
+}
+LogicException: Passed array specifies a non static method but no object (non-static method MyAutoLoader::dynaLoad() should not be called statically)
+int(0)
+====5====
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "autoLoad"
+}
+registered
+MyAutoLoader::autoLoad(NoExistingTestClass)
+Exception: Bla
+int(0)
+====6====
+array(2) {
+ [0]=>
+ object(MyAutoLoader)#%d (0) {
+ }
+ [1]=>
+ string(8) "dynaLoad"
+}
+registered
+MyAutoLoader::dynaLoad(NoExistingTestClass)
+Exception: Bla
+int(0)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_009.phpt b/ext/spl/tests/spl_autoload_009.phpt
new file mode 100644
index 0000000..d5e5413
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_009.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: spl_autoload() and friends
+--INI--
+include_path=.
+--FILE--
+<?php
+
+function my_autoload($name)
+{
+ require $name . '.class.inc';
+ var_dump(class_exists($name));
+}
+
+spl_autoload_register("spl_autoload");
+spl_autoload_register("my_autoload");
+
+$obj = new testclass;
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+%stestclass.inc
+%stestclass.class.inc
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_010.phpt b/ext/spl/tests/spl_autoload_010.phpt
new file mode 100644
index 0000000..cd70bdc
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_010.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: spl_autoload() and prepend
+--INI--
+include_path=.
+--FILE--
+<?php
+function autoloadA($name) {
+ echo "A -> $name\n";
+}
+function autoloadB($name) {
+ echo "B -> $name\n";
+}
+function autoloadC($name) {
+ echo "C -> $name\n";
+ class C{}
+}
+
+spl_autoload_register('autoloadA');
+spl_autoload_register('autoloadB', true, true);
+spl_autoload_register('autoloadC');
+
+new C;
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+B -> C
+A -> C
+C -> C
+===DONE===
diff --git a/ext/spl/tests/spl_autoload_011.phpt b/ext/spl/tests/spl_autoload_011.phpt
new file mode 100644
index 0000000..5a99255
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_011.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: spl_autoload() and object freed
+--INI--
+include_path=.
+--FILE--
+<?php
+class A {
+ public $var = 1;
+ public function autoload() {
+ echo "var:".$this->var."\n";
+ }
+ public function __destruct() {
+ echo "__destruct__\n";
+ }
+}
+
+$a = new A;
+$a->var = 2;
+
+spl_autoload_register(array($a, 'autoload'));
+unset($a);
+
+var_dump(class_exists("C", true));
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+var:2
+bool(false)
+===DONE===
+__destruct__
diff --git a/ext/spl/tests/spl_autoload_012.phpt b/ext/spl/tests/spl_autoload_012.phpt
new file mode 100644
index 0000000..e07f0e4
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_012.phpt
@@ -0,0 +1,65 @@
+--TEST--
+SPL: spl_autoload() capturing multiple Exceptions in __autoload
+--FILE--
+<?php
+
+function autoload_first($name)
+{
+ echo __METHOD__ . "\n";
+ throw new Exception('first');
+}
+
+function autoload_second($name)
+{
+ echo __METHOD__ . "\n";
+ throw new Exception('second');
+}
+
+spl_autoload_register('autoload_first');
+spl_autoload_register('autoload_second');
+
+try {
+ class_exists('ThisClassDoesNotExist');
+} catch(Exception $e) {
+ do {
+ echo $e->getMessage()."\n";
+ } while($e = $e->getPrevious());
+}
+
+try {
+ new ThisClassDoesNotExist;
+} catch(Exception $e) {
+ do {
+ echo $e->getMessage()."\n";
+ } while($e = $e->getPrevious());
+}
+
+class_exists('ThisClassDoesNotExist');
+?>
+===DONE===
+--EXPECTF--
+autoload_first
+autoload_second
+second
+first
+autoload_first
+autoload_second
+second
+first
+autoload_first
+autoload_second
+
+Fatal error: Uncaught exception 'Exception' with message 'first' in %sspl_autoload_012.php:%d
+Stack trace:
+#0 [internal function]: autoload_first('ThisClassDoesNo...')
+#1 [internal function]: spl_autoload_call('ThisClassDoesNo...')
+#2 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...')
+#3 {main}
+
+Next exception 'Exception' with message 'second' in %sspl_autoload_012.php:%d
+Stack trace:
+#0 [internal function]: autoload_second('ThisClassDoesNo...')
+#1 [internal function]: spl_autoload_call('ThisClassDoesNo...')
+#2 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...')
+#3 {main}
+ thrown in %sspl_autoload_012.php on line %d
diff --git a/ext/spl/tests/spl_autoload_013.phpt b/ext/spl/tests/spl_autoload_013.phpt
new file mode 100644
index 0000000..44d4d85
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_013.phpt
@@ -0,0 +1,51 @@
+--TEST--
+SPL: spl_autoload_functions() with closures and invokables
+--FILE--
+<?php
+$closure = function($class) {
+ echo "a called\n";
+};
+
+class Autoloader {
+ private $dir;
+ public function __construct($dir) {
+ $this->dir = $dir;
+ }
+ public function __invoke($class) {
+ var_dump("{$this->dir}/$class.php");
+ }
+}
+
+$al1 = new Autoloader('d1');
+$al2 = new Autoloader('d2');
+
+spl_autoload_register($closure);
+spl_autoload_register($al1);
+spl_autoload_register($al2);
+
+var_dump(spl_autoload_functions());
+
+?>
+===DONE===
+--EXPECTF--
+array(3) {
+ [0]=>
+ object(Closure)#%d (1) {
+ ["parameter"]=>
+ array(1) {
+ ["$class"]=>
+ string(10) "<required>"
+ }
+ }
+ [1]=>
+ object(Autoloader)#%d (1) {
+ ["dir":"Autoloader":private]=>
+ string(2) "d1"
+ }
+ [2]=>
+ object(Autoloader)#%d (1) {
+ ["dir":"Autoloader":private]=>
+ string(2) "d2"
+ }
+}
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_autoload_014.phpt b/ext/spl/tests/spl_autoload_014.phpt
new file mode 100644
index 0000000..a68fcb7
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_014.phpt
@@ -0,0 +1,47 @@
+--TEST--
+SPL: spl_autoload_unregister() with closures and invokables
+--FILE--
+<?php
+$closure = function($class) {
+ echo "closure called with class $class\n";
+};
+
+class Autoloader {
+ private $dir;
+ public function __construct($dir) {
+ $this->dir = $dir;
+ }
+ public function __invoke($class) {
+ echo ("Autoloader('{$this->dir}') called with $class\n");
+ }
+}
+
+class WorkingAutoloader {
+ public function __invoke($class) {
+ echo ("WorkingAutoloader() called with $class\n");
+ eval("class $class { }");
+ }
+}
+
+$al1 = new Autoloader('d1');
+$al2 = new WorkingAutoloader('d2');
+
+spl_autoload_register($closure);
+spl_autoload_register($al1);
+spl_autoload_register($al2);
+
+$x = new TestX;
+
+spl_autoload_unregister($closure);
+spl_autoload_unregister($al1);
+
+$y = new TestY;
+
+?>
+===DONE===
+--EXPECT--
+closure called with class TestX
+Autoloader('d1') called with TestX
+WorkingAutoloader() called with TestX
+WorkingAutoloader() called with TestY
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_autoload_bug48541.phpt b/ext/spl/tests/spl_autoload_bug48541.phpt
new file mode 100644
index 0000000..9937a7f
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_bug48541.phpt
@@ -0,0 +1,39 @@
+--TEST--
+SPL: spl_autoload_register() Bug #48541: registering multiple closures fails with memleaks
+--FILE--
+<?php
+
+class X {
+ public function getClosure() {
+ return function($class) {
+ echo "a2 called\n";
+ };
+ }
+}
+
+$a = function ($class) {
+ echo "a called\n";
+};
+$x = new X;
+$a2 = $x->getClosure();
+$b = function ($class) {
+ eval('class ' . $class . '{function __construct(){echo "foo\n";}}');
+ echo "b called\n";
+};
+spl_autoload_register($a);
+spl_autoload_register($a2);
+spl_autoload_register($b);
+
+$c = $a;
+$c2 = $a2;
+spl_autoload_register($c);
+spl_autoload_register($c2);
+$c = new foo;
+?>
+===DONE===
+--EXPECT--
+a called
+a2 called
+b called
+foo
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_autoload_call_basic.phpt b/ext/spl/tests/spl_autoload_call_basic.phpt
new file mode 100644
index 0000000..2bd65c2
--- /dev/null
+++ b/ext/spl/tests/spl_autoload_call_basic.phpt
@@ -0,0 +1,18 @@
+--TEST--
+spl_autoload_call() function - basic test for spl_autoload_call()
+--CREDITS--
+Jean-Marc Fontaine <jean-marc.fontaine@alterway.fr>
+# Alter Way Contribution Day 2011
+--FILE--
+<?php
+function customAutolader($class) {
+ require_once __DIR__ . '/testclass.class.inc';
+}
+spl_autoload_register('customAutolader');
+
+spl_autoload_call('TestClass');
+var_dump(class_exists('TestClass', false));
+?>
+--EXPECTF--
+%stestclass.class.inc
+bool(true)
diff --git a/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt b/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt
new file mode 100644
index 0000000..499cd67
--- /dev/null
+++ b/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt
@@ -0,0 +1,25 @@
+--TEST--
+SPL: CachingInterator constructor flag checks
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+ //line 681 ...
+ $array = array(array(7,8,9),1,2,3,array(4,5,6));
+$arrayIterator = new ArrayIterator($array);
+try {
+$test = new CachingIterator($arrayIterator, 0);
+$test = new CachingIterator($arrayIterator, 1);
+$test = new CachingIterator($arrayIterator, 2);
+$test = new CachingIterator($arrayIterator, 3); // this throws an exception
+} catch (InvalidArgumentException $e){
+ print $e->getMessage() . "\n";
+}
+
+
+?>
+===DONE===
+--EXPECTF--
+Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT
+===DONE===
diff --git a/ext/spl/tests/spl_cachingiterator___toString_basic.phpt b/ext/spl/tests/spl_cachingiterator___toString_basic.phpt
new file mode 100644
index 0000000..0395b37
--- /dev/null
+++ b/ext/spl/tests/spl_cachingiterator___toString_basic.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: SplCachingIterator, Test method to convert current element to string
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+$ai = new ArrayIterator(array(new stdClass(), new stdClass()));
+$ci = new CachingIterator($ai);
+var_dump(
+$ci->__toString() // if conversion to string is done by echo, for example, an exeption is thrown. Invoking __toString explicitly covers different code.
+);
+?>
+--EXPECTF--
+NULL
diff --git a/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt b/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt
new file mode 100644
index 0000000..126586b
--- /dev/null
+++ b/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: SplCachingIterator, Test method to set flags for caching iterator
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+$ai = new ArrayIterator(array('foo', 'bar'));
+
+$ci = new CachingIterator($ai);
+$ci->setFlags(); //expects arg
+
+?>
+--EXPECTF--
+Warning: CachingIterator::setFlags() expects exactly 1 parameter, %s
diff --git a/ext/spl/tests/spl_classes.phpt b/ext/spl/tests/spl_classes.phpt
new file mode 100644
index 0000000..172c4ab
--- /dev/null
+++ b/ext/spl/tests/spl_classes.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SPL: spl_classes() function
+--CREDITS--
+Sebastian Schürmann
+sebs@php.net
+Testfest 2009 Munich
+--FILE--
+<?php
+var_dump(is_array(spl_classes()));
+?>
+--EXPECT--
+bool(true)
+
diff --git a/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt b/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt
new file mode 100644
index 0000000..cee557e
--- /dev/null
+++ b/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: Spl File Info test getLinkTarget
+--CREDITS--
+Nataniel McHugh nat@fishtrap.co.uk
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+$link = __DIR__ . '/test_link';
+symlink(__FILE__, $link );
+$fileInfo = new SplFileInfo($link);
+
+if ($fileInfo->isLink()) {
+ echo $fileInfo->getLinkTarget() == __FILE__ ? 'same' : 'different',PHP_EOL;
+}
+var_dump(unlink($link));
+?>
+--EXPECT--
+same
+bool(true)
diff --git a/ext/spl/tests/spl_heap_count_basic.phpt b/ext/spl/tests/spl_heap_count_basic.phpt
new file mode 100644
index 0000000..6e6baf6
--- /dev/null
+++ b/ext/spl/tests/spl_heap_count_basic.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SPL: SplHeap, Test spl_heap_object_count_elements (spl_heap.c:490) for returning count() failure for Heaps
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class MyHeap extends SplHeap
+{
+ public function compare($a,$b)
+ {
+ return ($a < $b);
+ }
+
+ public function count() // override count to force failure
+ {
+ throw new Exception('Cause count to fail');
+ return parent::count();
+ }
+}
+
+
+$heap = new MyHeap();
+$heap->insert(1);
+count($heap);// refers to MyHeap->count() method
+
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'Exception' with message 'Cause count to fail' in %s
+Stack trace:
+#0 [internal function]: MyHeap->count()
+#1 %s count(Object(MyHeap))
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/spl_heap_count_error.phpt b/ext/spl/tests/spl_heap_count_error.phpt
new file mode 100644
index 0000000..6bed4cf
--- /dev/null
+++ b/ext/spl/tests/spl_heap_count_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: Priority queue count, illegal number of args
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+$h = new SplPriorityQueue();
+$h->count(1);
+?>
+--EXPECTF--
+Warning: SplPriorityQueue::count() expects exactly 0 parameters, 1 given in %s
diff --git a/ext/spl/tests/spl_heap_extract_parameter_error.phpt b/ext/spl/tests/spl_heap_extract_parameter_error.phpt
new file mode 100644
index 0000000..aecd03d
--- /dev/null
+++ b/ext/spl/tests/spl_heap_extract_parameter_error.phpt
@@ -0,0 +1,27 @@
+--TEST--
+SPL: Heap and extract with parameter
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+
+class TestHeap extends SplHeap {
+
+ function compare() {
+ print "This shouldn't be printed";
+ }
+}
+
+$testHeap = new TestHeap();
+
+
+
+var_dump($testHeap->extract('test'));
+
+?>
+===DONE===
+--EXPECTF--
+Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line 14
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_heap_insert_basic.phpt b/ext/spl/tests/spl_heap_insert_basic.phpt
new file mode 100644
index 0000000..76a34b2
--- /dev/null
+++ b/ext/spl/tests/spl_heap_insert_basic.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: SplHeap, Test method to insert into heap
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+class MyHeap extends SplHeap
+{
+ public function compare($a, $b)
+ {
+ return $a < $b;
+ }
+}
+
+$heap = new MyHeap();
+$heap->insert(1,2);
+?>
+--EXPECTF--
+Warning: SplHeap::insert() expects exactly 1 parameter, %s
diff --git a/ext/spl/tests/spl_heap_is_empty_basic.phpt b/ext/spl/tests/spl_heap_is_empty_basic.phpt
new file mode 100644
index 0000000..47d7ccc
--- /dev/null
+++ b/ext/spl/tests/spl_heap_is_empty_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplHeap, test trivial method to find if a heap is empty
+--CREDITS--
+Nathaniel McHugh nat@fishtrap.co.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class MyHeap extends SplHeap{
+
+public function compare($a, $b){
+return $a < $b;
+}
+
+}
+
+
+$heap = new MyHeap();
+var_dump($heap->isEmpty());
+$heap->insert(1);
+var_dump($heap->isEmpty());
+$heap->extract();
+var_dump($heap->isEmpty());
+$heap->isEmpty('var');
+?>
+--EXPECTF--
+bool(true)
+bool(false)
+bool(true)
+
+Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s
diff --git a/ext/spl/tests/spl_heap_isempty.phpt b/ext/spl/tests/spl_heap_isempty.phpt
new file mode 100644
index 0000000..2729c7f
--- /dev/null
+++ b/ext/spl/tests/spl_heap_isempty.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: Test of isEmpty for SPL Max Heap
+--CREDITS--
+Rohan Abraham (rohanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+ $h = new SplMaxHeap();
+ echo "Checking a new heap is empty: ";
+ var_dump($h->isEmpty())."\n";
+ $h->insert(2);
+ echo "Checking after insert: ";
+ var_dump($h->isEmpty())."\n";
+ $h->extract();
+ echo "Checking after extract: ";
+ var_dump($h->isEmpty())."\n";
+?>
+--EXPECT--
+Checking a new heap is empty: bool(true)
+Checking after insert: bool(false)
+Checking after extract: bool(true) \ No newline at end of file
diff --git a/ext/spl/tests/spl_heap_iteration_error.phpt b/ext/spl/tests/spl_heap_iteration_error.phpt
new file mode 100644
index 0000000..62e462f
--- /dev/null
+++ b/ext/spl/tests/spl_heap_iteration_error.phpt
@@ -0,0 +1,53 @@
+--TEST--
+SPL: Attempt to corrupt the heap while iterating
+--CREDITS--
+Lukasz Andrzejak meltir@meltir.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+class ext_heap extends SplMaxHeap {
+ public $fail = false;
+ public function compare($val1,$val2) {
+ if ($this->fail)
+ throw new Exception('Corrupting heap',99);
+ return 0;
+ }
+}
+
+$h = new ext_heap();
+$h->insert(array('foobar'));
+$h->insert(array('foobar1'));
+$h->insert(array('foobar2'));
+
+try {
+ $h->fail=true;
+ foreach ($h as $value) {};
+ echo "I should have raised an exception here";
+} catch (Exception $e) {
+ if ($e->getCode()!=99) echo "Unexpected exception";
+}
+
+var_dump($h);
+?>
+--EXPECTF--
+object(ext_heap)#%d (4) {
+ [%u|b%"fail"]=>
+ bool(true)
+ [%u|b%"flags":%u|b%"SplHeap":private]=>
+ int(0)
+ [%u|b%"isCorrupted":%u|b%"SplHeap":private]=>
+ bool(true)
+ [%u|b%"heap":%u|b%"SplHeap":private]=>
+ array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ %unicode|string%(7) "foobar2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ %unicode|string%(7) "foobar1"
+ }
+ }
+}
diff --git a/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt b/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt
new file mode 100644
index 0000000..8726f4b
--- /dev/null
+++ b/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt
@@ -0,0 +1,15 @@
+--TEST--
+SPL: SplHeap check no arguments to be accepted on recoverFromCorruption
+--CREDITS--
+Rohan Abraham (rohanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+ $h = new SplMaxHeap();
+ //Line below should throw a warning as no args are expected
+ $h->recoverFromCorruption("no args");
+?>
+--EXPECTF--
+
+Warning: SplHeap::recoverFromCorruption() expects exactly 0 parameters, 1 given in %s on line %d
+
diff --git a/ext/spl/tests/spl_iterator_apply_error.phpt b/ext/spl/tests/spl_iterator_apply_error.phpt
new file mode 100644
index 0000000..8e7cba4
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_apply_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+SPL: Error: iterator_apply when an iterator method (eg rewind) throws exception
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator {
+ public function rewind() {
+ throw new Exception('Make the iterator break');
+ }
+}
+
+function test() {}
+
+$it = new MyArrayIterator(array(1, 21, 22));
+
+try {
+ $res = iterator_apply($it, 'test');
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+
+<?php exit(0); ?>
+--EXPECT--
+Make the iterator break
diff --git a/ext/spl/tests/spl_iterator_apply_error_001.phpt b/ext/spl/tests/spl_iterator_apply_error_001.phpt
new file mode 100644
index 0000000..54663c0
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_apply_error_001.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: Error: iterator_apply when the callback throws an exception
+--FILE--
+<?php
+
+function test() {
+ throw new Exception('Broken callback');
+}
+
+$it = new RecursiveArrayIterator(array(1, 21, 22));
+
+try {
+ iterator_apply($it, 'test');
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Broken callback
diff --git a/ext/spl/tests/spl_iterator_caching_count_basic.phpt b/ext/spl/tests/spl_iterator_caching_count_basic.phpt
new file mode 100644
index 0000000..b11eb7b
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_caching_count_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: Caching iterator count() cache contents
+--CREDITS--
+Lukasz Andrzejak meltir@meltir.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$i = new ArrayIterator(array(1,1,1,1,1));
+$i = new CachingIterator($i,CachingIterator::FULL_CACHE);
+foreach ($i as $value) {
+ echo $i->count()."\n";
+}
+?>
+===DONE===
+--EXPECT--
+1
+2
+3
+4
+5
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_iterator_caching_count_error.phpt b/ext/spl/tests/spl_iterator_caching_count_error.phpt
new file mode 100644
index 0000000..70aa2be
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_caching_count_error.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: Caching iterator count() cache failure
+--CREDITS--
+Lukasz Andrzejak meltir@meltir.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$i = new ArrayIterator(array(1,1,1,1,1));
+$i = new CachingIterator($i);
+try {
+ $i->count();
+ echo "Should have caused an exception";
+} catch (BadMethodCallException $e) {
+ echo "Exception raised\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+Exception raised
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_iterator_caching_getcache_error.phpt b/ext/spl/tests/spl_iterator_caching_getcache_error.phpt
new file mode 100644
index 0000000..2ea4bd8
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_caching_getcache_error.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: Caching iterator getCache failure
+--CREDITS--
+Lukasz Andrzejak meltir@meltir.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$i = new ArrayIterator(array(1,1,1,1,1));
+$i = new CachingIterator($i);
+try {
+ $i->getCache();
+ echo "Should have caused an exception";
+} catch (BadMethodCallException $e) {
+ echo "Exception raised\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+Exception raised
+===DONE=== \ No newline at end of file
diff --git a/ext/spl/tests/spl_iterator_getcallchildren.phpt b/ext/spl/tests/spl_iterator_getcallchildren.phpt
new file mode 100644
index 0000000..77b03b6
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_getcallchildren.phpt
@@ -0,0 +1,39 @@
+--TEST--
+SPL: RecursiveIteratorIterator, getCallChildren
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+ //line 681 ...
+ $array = array(array(7,8,9),1,2,3,array(4,5,6));
+$recursiveArrayIterator = new RecursiveArrayIterator($array);
+$test = new RecursiveIteratorIterator($recursiveArrayIterator);
+
+var_dump($test->current());
+$test->next();
+var_dump($test->current());
+try {
+ $output = $test->callGetChildren();
+} catch (InvalidArgumentException $ilae){
+ $output = null;
+ print "invalid argument exception\n";
+}
+var_dump($output);
+
+
+?>
+===DONE===
+--EXPECTF--
+ array(3) {
+ [0]=>
+ int(7)
+ [1]=>
+ int(8)
+ [2]=>
+ int(9)
+}
+int(7)
+invalid argument exception
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_iterator_iterator_constructor.phpt b/ext/spl/tests/spl_iterator_iterator_constructor.phpt
new file mode 100644
index 0000000..d4fdb14
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_iterator_constructor.phpt
@@ -0,0 +1,30 @@
+--TEST--
+SPL: IteratorInterator constructor checks
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+
+ //I think this is testing line 1297 of spl_iterators.c
+
+ $array = array(array(7,8,9),1,2,3,array(4,5,6));
+$arrayIterator = new ArrayIterator($array);
+try {
+$test = new IteratorIterator($arrayIterator);
+
+$test = new IteratorIterator($arrayIterator, 1);
+$test = new IteratorIterator($arrayIterator, 1, 1);
+$test = new IteratorIterator($arrayIterator, 1, 1, 1);
+$test = new IteratorIterator($arrayIterator, 1, 1, 1, 1);
+
+} catch (InvalidArgumentException $e){
+ print $e->getMessage() . "\n";
+}
+
+
+?>
+===DONE===
+--EXPECTF--
+IteratorIterator::__construct() expects at most 2 parameters, 3 given
+===DONE===
diff --git a/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt b/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt
new file mode 100644
index 0000000..0d45c31
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt
@@ -0,0 +1,16 @@
+--TEST--
+SPL: IteratorIterator foreach by reference failure
+--CREDITS--
+Lukasz Andrzejak meltir@meltir.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+$i = new ArrayIterator(array(1,1,1,1,1));
+$iii = new IteratorIterator($i);
+p($iii);
+function p ($i) {
+ foreach ($i as &$value) {}
+}
+?>
+--EXPECTF--
+Fatal error: An iterator cannot be used with foreach by reference in %s \ No newline at end of file
diff --git a/ext/spl/tests/spl_iterator_to_array_basic.phpt b/ext/spl/tests/spl_iterator_to_array_basic.phpt
new file mode 100644
index 0000000..68cb879
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_to_array_basic.phpt
@@ -0,0 +1,13 @@
+--TEST--
+SPL: iterator_to_array, Test function to convert iterator to array
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+iterator_to_array();//requires iterator as arg
+
+?>
+--EXPECTF--
+Warning: iterator_to_array() expects at least 1 parameter, %s
diff --git a/ext/spl/tests/spl_iterator_to_array_error.phpt b/ext/spl/tests/spl_iterator_to_array_error.phpt
new file mode 100644
index 0000000..755ef7b
--- /dev/null
+++ b/ext/spl/tests/spl_iterator_to_array_error.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: Error: iterator_to_array when the current operation throws an exception
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator {
+ public function current() {
+ throw new Exception('Make the iterator break');
+ }
+}
+
+$it = new MyArrayIterator(array(4, 6, 2));
+
+try {
+ // get keys
+ $ar = iterator_to_array($it);
+} catch (Exception $e) {
+ echo $e->getMessage() . PHP_EOL;
+}
+
+try {
+ // get values
+ $ar = iterator_to_array($it, false);
+} catch (Exception $e) {
+ echo $e->getMessage() . PHP_EOL;
+}
+
+?>
+
+<?php exit(0); ?>
+--EXPECT--
+Make the iterator break
+Make the iterator break
diff --git a/ext/spl/tests/spl_limit_iterator_check_limits.phpt b/ext/spl/tests/spl_limit_iterator_check_limits.phpt
new file mode 100644
index 0000000..ae1bc85
--- /dev/null
+++ b/ext/spl/tests/spl_limit_iterator_check_limits.phpt
@@ -0,0 +1,37 @@
+--TEST--
+SPL: LimitIterator check limits are valid
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+ $array = array(array(7,8,9),1,2,3,array(4,5,6));
+$arrayIterator = new ArrayIterator($array);
+
+try {
+ $limitIterator = new LimitIterator($arrayIterator, -1);
+} catch (OutOfRangeException $e){
+ print $e->getMessage(). "\n";
+}
+
+
+try {
+ $limitIterator = new LimitIterator($arrayIterator, 0, -2);
+} catch (OutOfRangeException $e){
+ print $e->getMessage() . "\n";
+}
+
+try {
+ $limitIterator = new LimitIterator($arrayIterator, 0, -1);
+} catch (OutOfRangeException $e){
+ print $e->getMessage() . "\n";
+}
+
+
+
+?>
+===DONE===
+--EXPECTF--
+Parameter offset must be >= 0
+Parameter count must either be -1 or a value greater than or equal 0
+===DONE===
diff --git a/ext/spl/tests/spl_maxheap_compare_basic.phpt b/ext/spl/tests/spl_maxheap_compare_basic.phpt
new file mode 100644
index 0000000..3705b3f
--- /dev/null
+++ b/ext/spl/tests/spl_maxheap_compare_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+SPL: SplMaxHeap, Test method to comare elements
+--CREDITS--
+Chris Scott chris.scott@nstein.com
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+class MyHeap extends SplMaxHeap
+{
+ public function testCompare()
+ {
+ return parent::compare(1);
+ }
+}
+
+$heap = new MyHeap();
+$heap->testCompare();
+
+?>
+--EXPECTF--
+Warning: SplMaxHeap::compare() expects exactly 2 parameters, %s
diff --git a/ext/spl/tests/spl_minheap_compare_error.phpt b/ext/spl/tests/spl_minheap_compare_error.phpt
new file mode 100644
index 0000000..7120a6c
--- /dev/null
+++ b/ext/spl/tests/spl_minheap_compare_error.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: SplMinHeap compare, illegal number of args
+--CREDITS--
+Mark Schaschke (mark@fractalturtle.com)
+TestFest London May 2009
+--FILE--
+<?php
+class SplMinHeap2 extends SplMinHeap {
+ public function testCompare1() {
+ return parent::compare();
+ }
+ public function testCompare2() {
+ return parent::compare(1);
+ }
+ public function testCompare3() {
+ return parent::compare(1, 2, 3);
+ }
+}
+
+$h = new SplMinHeap2();
+$h->testCompare1();
+$h->testCompare2();
+$h->testCompare3();
+?>
+--EXPECTF--
+Warning: SplMinHeap::compare() expects exactly 2 parameters, 0 given in %s
+
+Warning: SplMinHeap::compare() expects exactly 2 parameters, 1 given in %s
+
+Warning: SplMinHeap::compare() expects exactly 2 parameters, 3 given in %s
+
diff --git a/ext/spl/tests/spl_pq_top_basic.phpt b/ext/spl/tests/spl_pq_top_basic.phpt
new file mode 100644
index 0000000..dcc1cbe
--- /dev/null
+++ b/ext/spl/tests/spl_pq_top_basic.phpt
@@ -0,0 +1,42 @@
+--TEST--
+SPL: SplPriorityQueue: top and extract flags
+--CREDITS--
+Nathaniel McHugh nat@fishtrap.co.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+
+$priorityQueue = new SplPriorityQueue();
+
+$priorityQueue->insert("a", 1);
+$priorityQueue->insert("b", 2);
+$priorityQueue->insert("c", 0);
+
+echo "EXTR DEFAULT",PHP_EOL;
+echo "value: ",$priorityQueue->top(),PHP_EOL;
+
+$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
+echo "EXTR_PRIORITY",PHP_EOL;
+echo "priority: ",$priorityQueue->top(),PHP_EOL;
+
+$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
+echo "EXTR_BOTH",PHP_EOL;
+print_r($priorityQueue->top());
+
+echo "EXTR_DATA",PHP_EOL;
+$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_DATA);
+echo "value: ",$priorityQueue->top(),PHP_EOL;
+?>
+--EXPECT--
+EXTR DEFAULT
+value: b
+EXTR_PRIORITY
+priority: 2
+EXTR_BOTH
+Array
+(
+ [data] => b
+ [priority] => 2
+)
+EXTR_DATA
+value: b \ No newline at end of file
diff --git a/ext/spl/tests/spl_pq_top_error_args.phpt b/ext/spl/tests/spl_pq_top_error_args.phpt
new file mode 100644
index 0000000..a0e5969
--- /dev/null
+++ b/ext/spl/tests/spl_pq_top_error_args.phpt
@@ -0,0 +1,12 @@
+--TEST--
+SPL: SplPriorityQueue: top too many arguments exception
+--CREDITS--
+Nathaniel McHugh nat@fishtrap.co.uk
+#testfest London 2009-05-09
+--FILE--
+<?php
+$priorityQueue = new SplPriorityQueue();
+$priorityQueue->top('var');
+?>
+--EXPECTF--
+Warning: SplPriorityQueue::top() expects exactly 0 parameters, 1 given in %s \ No newline at end of file
diff --git a/ext/spl/tests/spl_pq_top_error_corrupt.phpt b/ext/spl/tests/spl_pq_top_error_corrupt.phpt
new file mode 100644
index 0000000..30b6fde
--- /dev/null
+++ b/ext/spl/tests/spl_pq_top_error_corrupt.phpt
@@ -0,0 +1,38 @@
+--TEST--
+SPL: SplPriorityQueue: top and extract flags
+--CREDITS--
+Nathaniel McHugh nat@fishtrap.co.uk
+#testfest 2009-05-09
+--FILE--
+<?php
+
+class myPriorityQueue extends SplPriorityQueue{
+
+ public function compare($a, $b){
+ if ($b == 2) {
+ throw new Exception('ignore me');
+ } else {
+ return parent::compare($a, $b);
+ }
+ }
+}
+
+$priorityQueue = new myPriorityQueue();
+$priorityQueue->insert("a", 1);
+
+try {
+ //corrupt heap
+ $priorityQueue->insert("b", 2);
+ // ignore exception tested elsewhere
+} catch (Exception $e) {
+}
+
+try {
+ $priorityQueue->top();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage().PHP_EOL;
+}
+
+?>
+--EXPECT--
+Exception: Heap is corrupted, heap properties are no longer ensured.
diff --git a/ext/spl/tests/spl_pq_top_error_empty.phpt b/ext/spl/tests/spl_pq_top_error_empty.phpt
new file mode 100644
index 0000000..9e2a31b
--- /dev/null
+++ b/ext/spl/tests/spl_pq_top_error_empty.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: SplPriorityQueue: top exception on empty heap
+--CREDITS--
+Nathaniel McHugh nat@fishtrap.co.uk
+#testfest 2009-05-09
+--FILE--
+<?php
+
+$priorityQueue = new SplPriorityQueue();
+
+try {
+ $priorityQueue->top();
+} catch (RuntimeException $e) {
+ echo "Exception: ".$e->getMessage().PHP_EOL;
+}
+
+?>
+--EXPECT--
+Exception: Can't peek at an empty heap
diff --git a/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt b/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt
new file mode 100644
index 0000000..659ffb4
--- /dev/null
+++ b/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt
@@ -0,0 +1,31 @@
+--TEST--
+SPL: priorityQueue paramter test on insert method
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+
+
+$testHeap = new SplPriorityQueue();
+
+
+var_dump($testHeap->insert());
+var_dump($testHeap->insert('test'));
+var_dump($testHeap->insert('test', 'test'));
+var_dump($testHeap->insert('test', 'test', 'test'));
+
+
+?>
+===DONE===
+--EXPECTF--
+Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 0 given in %s on line 7
+NULL
+
+Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 1 given in %s on line 8
+NULL
+bool(true)
+
+Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 3 given in %s on line 10
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt b/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt
new file mode 100644
index 0000000..d52a320
--- /dev/null
+++ b/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt
@@ -0,0 +1,28 @@
+--TEST--
+SPL: RecursiveIteratorIterator, setMaxDepth check parameter count
+--CREDITS--
+Sean Burlington www.practicalweb.co.uk
+TestFest London May 2009
+--FILE--
+<?php
+ //line 681 ...
+ $array = array(array(7,8,9),1,2,3,array(4,5,6));
+$recursiveArrayIterator = new RecursiveArrayIterator($array);
+$test = new RecursiveIteratorIterator($recursiveArrayIterator);
+
+//var_dump($test->current());
+$test->setMaxDepth();
+$test->setMaxDepth(1);
+$test->setMaxDepth(1,2);
+$test->setMaxDepth(1,2,3);
+
+//var_dump($test->current());
+
+
+?>
+===DONE===
+--EXPECTF--
+Warning: RecursiveIteratorIterator::setMaxDepth() expects at most 1 parameter, 2 given in %s on line 10
+
+Warning: RecursiveIteratorIterator::setMaxDepth() expects at most 1 parameter, 3 given in %s on line 11
+===DONE===
diff --git a/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt b/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt
new file mode 100644
index 0000000..1262ec0
--- /dev/null
+++ b/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt
@@ -0,0 +1,33 @@
+--TEST--
+SPL: Test on RecursiveIteratorIterator key function checking switch statements
+--CREDITS--
+Rohan Abraham (rohanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+ $ar = array("one"=>1, "two"=>2, "three"=>array("four"=>4, "five"=>5, "six"=>array("seven"=>7)), "eight"=>8, -100 => 10, NULL => "null");
+ $it = new RecursiveArrayIterator($ar);
+ $it = new RecursiveIteratorIterator($it);
+ foreach($it as $k=>$v)
+ {
+ echo "$k=>$v\n";
+ var_dump($k);
+ }
+?>
+--EXPECTF--
+one=>1
+%unicode|string%(3) "one"
+two=>2
+%unicode|string%(3) "two"
+four=>4
+%unicode|string%(4) "four"
+five=>5
+%unicode|string%(4) "five"
+seven=>7
+%unicode|string%(5) "seven"
+eight=>8
+%unicode|string%(5) "eight"
+-100=>10
+int(-100)
+=>null
+%unicode|string%(0) ""
diff --git a/ext/spl/tests/splfixedarray_offsetExists_larger.phpt b/ext/spl/tests/splfixedarray_offsetExists_larger.phpt
new file mode 100644
index 0000000..9449d64
--- /dev/null
+++ b/ext/spl/tests/splfixedarray_offsetExists_larger.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Checks that offsetExists() does not accept a value larger than the array.
+--CREDITS--
+ PHPNW Test Fest 2009 - Rick Ogden
+--FILE--
+<?php
+$ar = new SplFixedArray(3);
+$ar[0] = 1;
+$ar[1] = 2;
+$ar[2] = 3;
+
+var_dump($ar->offsetExists(4));
+?>
+--EXPECT--
+bool(false)
diff --git a/ext/spl/tests/splpriorityqueue_extract.phpt b/ext/spl/tests/splpriorityqueue_extract.phpt
new file mode 100644
index 0000000..eee7bb2
--- /dev/null
+++ b/ext/spl/tests/splpriorityqueue_extract.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SPL: splpriorityqueue extract() Test arguments
+--CREDITS--
+Roshan Abraham (roshanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+
+$sp = new SplPriorityQueue();
+
+$sp->insert("1",1);
+
+$sp->extract(1); // Should throw a warning as extract expects NO arguments
+
+?>
+--EXPECTF--
+
+Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d
+
diff --git a/ext/spl/tests/splpriorityqueue_setextractflags.phpt b/ext/spl/tests/splpriorityqueue_setextractflags.phpt
new file mode 100644
index 0000000..97d86f3
--- /dev/null
+++ b/ext/spl/tests/splpriorityqueue_setextractflags.phpt
@@ -0,0 +1,17 @@
+--TEST--
+SPL: splpriorityqueue setExtractFlags() Test arguments
+--CREDITS--
+Roshan Abraham (roshanabrahams@gmail.com)
+TestFest London May 2009
+--FILE--
+<?php
+
+$sp = new SplPriorityQueue();
+
+$sp->setExtractFlags(1,1); // Should throw a warning as setExtractFlags expects only 1 argument
+
+?>
+--EXPECTF--
+
+Warning: SplPriorityQueue::setExtractFlags() expects exactly 1 parameter, 2 given in %s on line %d
+
diff --git a/ext/spl/tests/testclass b/ext/spl/tests/testclass
new file mode 100755
index 0000000..ceb24c8
--- /dev/null
+++ b/ext/spl/tests/testclass
@@ -0,0 +1,5 @@
+<?php
+
+echo __FILE__ . "\n";
+
+?> \ No newline at end of file
diff --git a/ext/spl/tests/testclass.class.inc b/ext/spl/tests/testclass.class.inc
new file mode 100644
index 0000000..f5fe741
--- /dev/null
+++ b/ext/spl/tests/testclass.class.inc
@@ -0,0 +1,9 @@
+<?php
+
+echo __FILE__ . "\n";
+
+class TestClass
+{
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/tests/testclass.inc b/ext/spl/tests/testclass.inc
new file mode 100644
index 0000000..ceb24c8
--- /dev/null
+++ b/ext/spl/tests/testclass.inc
@@ -0,0 +1,5 @@
+<?php
+
+echo __FILE__ . "\n";
+
+?> \ No newline at end of file
diff --git a/ext/spl/tests/testclass.php.inc b/ext/spl/tests/testclass.php.inc
new file mode 100644
index 0000000..ceb24c8
--- /dev/null
+++ b/ext/spl/tests/testclass.php.inc
@@ -0,0 +1,5 @@
+<?php
+
+echo __FILE__ . "\n";
+
+?> \ No newline at end of file