helly Sat Mar 12 18:03:33 2005 EDT Added files: /php-src/ext/spl/tests iterator_021.phpt iterator_022.phpt
Modified files: /php-src/ext/spl spl.php spl_exceptions.c spl_exceptions.h spl_iterators.c Log: - Allow to hook into RecursiveIteratorIterator's child handling - Better=faster function caching for RecursiveIteratorIterator - Check for exceptions and fix check for illegal return values - Add UnexpectedValueException - Add docu
http://cvs.php.net/diff.php/php-src/ext/spl/spl.php?r1=1.45&r2=1.46&ty=u Index: php-src/ext/spl/spl.php diff -u php-src/ext/spl/spl.php:1.45 php-src/ext/spl/spl.php:1.46 --- php-src/ext/spl/spl.php:1.45 Tue Mar 8 20:21:04 2005 +++ php-src/ext/spl/spl.php Sat Mar 12 18:03:31 2005 @@ -252,6 +252,8 @@ * * This kind of exception should be used to inform about domain erors in * mathematical sense. + * + * @see RangeException */ class DomainException extends LogicException { @@ -260,6 +262,8 @@ /** @ingroup SPL * @brief Exception that denotes invalid arguments were passed. * @since PHP 5.1 + * + * @see UnexpectedValueException */ class InvalidArgumentException extends LogicException { @@ -321,19 +325,36 @@ * @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 http://cvs.php.net/diff.php/php-src/ext/spl/spl_exceptions.c?r1=1.4&r2=1.5&ty=u Index: php-src/ext/spl/spl_exceptions.c diff -u php-src/ext/spl/spl_exceptions.c:1.4 php-src/ext/spl/spl_exceptions.c:1.5 --- php-src/ext/spl/spl_exceptions.c:1.4 Mon Nov 1 15:57:23 2004 +++ php-src/ext/spl/spl_exceptions.c Sat Mar 12 18:03:31 2005 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_exceptions.c,v 1.4 2004/11/01 20:57:23 helly Exp $ */ +/* $Id: spl_exceptions.c,v 1.5 2005/03/12 23:03:31 helly Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -45,6 +45,7 @@ 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() @@ -64,6 +65,7 @@ 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; } http://cvs.php.net/diff.php/php-src/ext/spl/spl_exceptions.h?r1=1.3&r2=1.4&ty=u Index: php-src/ext/spl/spl_exceptions.h diff -u php-src/ext/spl/spl_exceptions.h:1.3 php-src/ext/spl/spl_exceptions.h:1.4 --- php-src/ext/spl/spl_exceptions.h:1.3 Mon Nov 1 15:57:23 2004 +++ php-src/ext/spl/spl_exceptions.h Sat Mar 12 18:03:31 2005 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_exceptions.h,v 1.3 2004/11/01 20:57:23 helly Exp $ */ +/* $Id: spl_exceptions.h,v 1.4 2005/03/12 23:03:31 helly Exp $ */ #ifndef SPL_EXCEPTIONS_H #define SPL_EXCEPTIONS_H @@ -37,6 +37,7 @@ 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); http://cvs.php.net/diff.php/php-src/ext/spl/spl_iterators.c?r1=1.66&r2=1.67&ty=u Index: php-src/ext/spl/spl_iterators.c diff -u php-src/ext/spl/spl_iterators.c:1.66 php-src/ext/spl/spl_iterators.c:1.67 --- php-src/ext/spl/spl_iterators.c:1.66 Sun Mar 6 18:07:43 2005 +++ php-src/ext/spl/spl_iterators.c Sat Mar 12 18:03:31 2005 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_iterators.c,v 1.66 2005/03/06 23:07:43 helly Exp $ */ +/* $Id: spl_iterators.c,v 1.67 2005/03/12 23:03:31 helly Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -85,6 +85,8 @@ spl_sub_iterator *iterators; int level; RecursiveIteratorMode mode; + zend_function *callHasChildren; + zend_function *callGetChildren; zend_function *beginChildren; zend_function *endChildren; zend_class_entry *ce; @@ -183,7 +185,11 @@ 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); @@ -211,13 +217,17 @@ 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) { @@ -234,7 +244,7 @@ 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; @@ -244,7 +254,7 @@ 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 { @@ -335,9 +345,23 @@ 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++; @@ -443,6 +467,40 @@ 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) @@ -538,10 +596,12 @@ 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} }; http://cvs.php.net/co.php/php-src/ext/spl/tests/iterator_021.phpt?r=1.1&p=1 Index: php-src/ext/spl/tests/iterator_021.phpt +++ php-src/ext/spl/tests/iterator_021.phpt --TEST-- SPL: RecursiveIteratorIterator and hasChildren --FILE-- <?php class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator { function hasChildren() { return is_array($this->current()); } function getChildren() { echo __METHOD__ . "\n"; return new RecursiveArrayIterator($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 beginChildren() { echo __METHOD__ . "(".$this->getDepth().")\n"; } function endChildren() { echo __METHOD__ . "(".$this->getDepth().")\n"; } } foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(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); ?> --EXPECTF-- RecursiveArrayIteratorIterator::rewind RecursiveArrayIteratorIterator::callHasChildren(0) = no/no RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>a RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes RecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::callHasChildren(1) = no/no RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>ba RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes RecursiveArrayIterator::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 RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes RecursiveArrayIterator::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 RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(0) RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes RecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::callHasChildren(1) = no/no RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>ca RecursiveArrayIteratorIterator::next RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(0) RecursiveArrayIteratorIterator::callHasChildren(0) = no/no RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 3=>d RecursiveArrayIteratorIterator::next RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::valid RecursiveArrayIterator::valid = false ===DONE=== http://cvs.php.net/co.php/php-src/ext/spl/tests/iterator_022.phpt?r=1.1&p=1 Index: php-src/ext/spl/tests/iterator_022.phpt +++ php-src/ext/spl/tests/iterator_022.phpt --TEST-- SPL: RecursiveIteratorIterator and callHasChildren/callGetChildren --FILE-- <?php class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator { function hasChildren() { return is_array($this->current()); } 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 RecursiveArrayIterator($this->current()); } function beginChildren() { echo __METHOD__ . "(".$this->getDepth().")\n"; } function endChildren() { echo __METHOD__ . "(".$this->getDepth().")\n"; } } try { foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(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); ?> --EXPECTF-- 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 RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) 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 RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(0) RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes RecursiveArrayIteratorIterator::callGetChildren(skip) Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator ===DONE===
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php