success = SUCCESS;
} else {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %v::%s()", intern->inner.ce->name, method);
success = FAILURE;
}
}
#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 %v must call %v::__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 spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_inner, dual_it_type dit_type)
+inline 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;
+ 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, "%v::getIterator() must be called exactly once per instance", ce_base->name);
+ return NULL;
+ }
php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
- intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
-
intern->dit_type = dit_type;
switch (dit_type) {
case DIT_LimitIterator: {
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 (!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 implememnts Traversable", ce->name);
+ zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%v::getIterator() must return an object that implememnts Traversable", ce->name);
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return NULL;
}
/* {{{ proto FilterIterator::__construct(Iterator it)
Create an Iterator from another iterator */
-SPL_METHOD(dual_it, __construct)
+SPL_METHOD(FilterIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_Default);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
} /* }}} */
/* {{{ proto Iterator FilterIterator::getInnerIterator()
Create a RecursiveFilterIterator from a RecursiveIterator */
SPL_METHOD(RecursiveFilterIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_Default);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
} /* }}} */
/* {{{ proto boolean RecursiveFilterIterator::hasChildren()
Create a ParentIterator from a RecursiveIterator */
SPL_METHOD(ParentIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_Default);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
} /* }}} */
/* {{{ proto boolean ParentIterator::hasChildren()
Create an RegExIterator from another iterator and a regular expression */
SPL_METHOD(RegExIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_RegExIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegExIterator, zend_ce_iterator, DIT_RegExIterator);
} /* }}} */
/* {{{ proto bool RegExIterator::accept()
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_RecursiveIterator, DIT_RecursiveRegExIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegExIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegExIterator);
} /* }}} */
#endif
if (object->dit_type == DIT_AppendIterator) {
object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
- zval_ptr_dtor(&object->u.append.zarrayit);
+ if (object->u.append.zarrayit) {
+ zval_ptr_dtor(&object->u.append.zarrayit);
+ }
}
if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
intern = emalloc(sizeof(spl_dual_it_object));
memset(intern, 0, sizeof(spl_dual_it_object));
intern->std.ce = class_type;
+ intern->dit_type = DIT_Unknown;
ALLOC_HASHTABLE(intern->std.properties);
zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_FilterIterator[] = {
- SPL_ME(dual_it, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
SPL_ME(FilterIterator, rewind, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
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, zend_ce_iterator, DIT_LimitIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
} /* }}} */
/* {{{ proto void LimitIterator::rewind()
Construct a CachingIterator from an Iterator */
SPL_METHOD(CachingIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_CachingIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
} /* }}} */
/* {{{ proto void CachingIterator::rewind()
Create an iterator from a RecursiveIterator */
SPL_METHOD(RecursiveCachingIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
} /* }}} */
/* {{{ proto bolean RecursiveCachingIterator::hasChildren()
Create an iterator from anything that is traversable */
SPL_METHOD(IteratorIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_traversable, DIT_IteratorIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
} /* }}} */
static
Create an iterator from another iterator */
SPL_METHOD(NoRewindIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_NoRewindIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
} /* }}} */
/* {{{ proto void NoRewindIterator::rewind()
Create an iterator from another iterator */
SPL_METHOD(InfiniteIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_InfiniteIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
} /* }}} */
/* {{{ proto InfiniteIterator::next()
Create an AppendIterator */
SPL_METHOD(AppendIterator, __construct)
{
- spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_AppendIterator);
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
} /* }}} */
/* {{{ proto void AppendIterator::append(Iterator it)
zval *it;
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ APPENDIT_CHECK_CTOR(intern);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
return;
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ APPENDIT_CHECK_CTOR(intern);
spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
} /* }}} */
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ APPENDIT_CHECK_CTOR(intern);
RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
} /* }}} */