Skip to content

Commit

Permalink
- Allow to hook into RecursiveIteratorIterator's child handling
Browse files Browse the repository at this point in the history
- Better=faster function caching for RecursiveIteratorIterator
- Check for exceptions and fix check for illegal return values
- Add UnexpectedValueException
- Add docu
  • Loading branch information
helly25 committed Mar 12, 2005
1 parent 6dc04d9 commit f9de3fd
Show file tree
Hide file tree
Showing 6 changed files with 473 additions and 13 deletions.
23 changes: 22 additions & 1 deletion ext/spl/spl.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ class BadMethodCallException extends BadFunctionCallException
*
* This kind of exception should be used to inform about domain erors in
* mathematical sense.
*
* @see RangeException
*/
class DomainException extends LogicException
{
Expand All @@ -260,6 +262,8 @@ class DomainException extends LogicException
/** @ingroup SPL
* @brief Exception that denotes invalid arguments were passed.
* @since PHP 5.1
*
* @see UnexpectedValueException
*/
class InvalidArgumentException extends LogicException
{
Expand Down Expand Up @@ -321,19 +325,36 @@ class OverflowException extends RuntimeException
* @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 Exception thrown to indicate arithmetic/buffer underflow.
* @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
Expand Down
2 changes: 2 additions & 0 deletions ext/spl/spl_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ 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()

Expand All @@ -64,6 +65,7 @@ PHP_MINIT_FUNCTION(spl_exceptions)
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;
}
Expand Down
1 change: 1 addition & 0 deletions ext/spl/spl_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ 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);

Expand Down
84 changes: 72 additions & 12 deletions ext/spl/spl_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ typedef struct _spl_recursive_it_object {
spl_sub_iterator *iterators;
int level;
RecursiveIteratorMode mode;
zend_function *callHasChildren;
zend_function *callGetChildren;
zend_function *beginChildren;
zend_function *endChildren;
zend_class_entry *ce;
Expand Down Expand Up @@ -183,7 +185,11 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
case RS_TEST:
ce = object->iterators[object->level].ce;
zobject = object->iterators[object->level].zobject;
zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
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 (retval) {
has_children = zend_is_true(retval);
zval_ptr_dtor(&retval);
Expand Down Expand Up @@ -211,13 +217,17 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
case RS_CHILD:
ce = object->iterators[object->level].ce;
zobject = object->iterators[object->level].zobject;
zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
ce = child ? Z_OBJCE_P(child) : NULL;
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);
}
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_InvalidArgumentException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
return;
}
if (object->mode == RIT_CHILD_FIRST) {
Expand All @@ -234,7 +244,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
if (sub_iter->funcs->rewind) {
sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
}
if (!object->beginChildren || object->beginChildren->common.scope != spl_ce_RecursiveIteratorIterator) {
if (object->beginChildren) {
zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
}
goto next_step;
Expand All @@ -244,7 +254,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
iterator->funcs->dtor(iterator TSRMLS_CC);
zval_ptr_dtor(&object->iterators[object->level].zobject);
object->level--;
if (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator) {
if (object->endChildren) {
zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
}
} else {
Expand Down Expand Up @@ -335,9 +345,23 @@ SPL_METHOD(RecursiveIteratorIterator, __construct)
intern->iterators = emalloc(sizeof(spl_sub_iterator));
intern->level = 0;
intern->mode = mode;
intern->beginChildren = NULL;
intern->endChildren = NULL;
intern->ce = Z_OBJCE_P(object);
zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
if (intern->callHasChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
intern->callHasChildren = NULL;
}
zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
if (intern->callGetChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
intern->callGetChildren = NULL;
}
zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
if (intern->beginChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
intern->beginChildren = NULL;
}
zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
if (intern->endChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
intern->endChildren = 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 TSRMLS_CC);
iterator->refcount++;
Expand Down Expand Up @@ -443,6 +467,40 @@ SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
} /* }}} */

/* {{{ 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;

zobject = object->iterators[object->level].zobject;
if (!zobject) {
RETURN_FALSE;
} else {
zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
RETURN_ZVAL(retval, 0, 1);
}
} /* }}} */

/* {{{ 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;

zobject = object->iterators[object->level].zobject;
if (!zobject) {
return;
} else {
zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
RETURN_ZVAL(retval, 0, 1);
}
} /* }}} */

/* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginChildren()
Called when recursing one level down */
SPL_METHOD(RecursiveIteratorIterator, beginChildren)
Expand Down Expand Up @@ -538,10 +596,12 @@ static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
SPL_ME(RecursiveIteratorIterator, current, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, next, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, getDepth, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, getSubIterator,arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, getInnerIterator,NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, beginChildren, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, endChildren, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, callHasChildren, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, callGetChildren, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, beginChildren, NULL, ZEND_ACC_PUBLIC)
SPL_ME(RecursiveIteratorIterator, endChildren, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};

Expand Down
Loading

0 comments on commit f9de3fd

Please sign in to comment.