From: Marcus Boerger Date: Wed, 17 Mar 2004 19:58:32 +0000 (+0000) Subject: Fix CachingIterator's ability to cache string conversion results. X-Git-Tag: php-5.0.0RC1~20 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=851c254ef8eae8752077438f8e2e54e29af9aaa8;p=php Fix CachingIterator's ability to cache string conversion results. Add a test for that. --- diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 143ff9f6b6..59cfd3b00c 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -1054,6 +1054,10 @@ static INLINE void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) zval_ptr_dtor(&retval); } if (intern->u.caching.flags & CIT_CALL_TOSTRING) { +#if MBO_0 + /* This version requires zend_make_printable_zval() being able to + * call __toString(). + */ int use_copy; zval expr_copy; ALLOC_ZVAL(intern->u.caching.zstr); @@ -1067,6 +1071,29 @@ static INLINE void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) } else { zval_copy_ctor(intern->u.caching.zstr); } +#else + zval expr_copy; + if (intern->current.data->value.obj.handlers->cast_object && + intern->current.data->value.obj.handlers->cast_object(intern->current.data, &expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) + { + ALLOC_ZVAL(intern->u.caching.zstr); + *intern->u.caching.zstr = expr_copy; + INIT_PZVAL(intern->u.caching.zstr); + zval_copy_ctor(intern->u.caching.zstr); + zval_dtor(&expr_copy); + } else { + zend_class_entry *ce_data = spl_get_class_entry(intern->current.data TSRMLS_CC); + if (ce_data && zend_hash_exists(&ce_data->function_table, "__tostring", sizeof("__tostring"))) { + zend_call_method_with_0_params(&intern->current.data, ce_data, NULL, "__tostring", &intern->u.caching.zstr); + } else { + ALLOC_ZVAL(intern->u.caching.zstr); + *intern->u.caching.zstr = *intern->current.data; + zval_copy_ctor(intern->u.caching.zstr); + INIT_PZVAL(intern->u.caching.zstr); + convert_to_string(intern->u.caching.zstr); + } + } +#endif } spl_dual_it_next(intern, 0 TSRMLS_CC); } else { diff --git a/ext/spl/tests/caching_iterator_str.phpt b/ext/spl/tests/caching_iterator_str.phpt new file mode 100755 index 0000000000..c60776cb33 --- /dev/null +++ b/ext/spl/tests/caching_iterator_str.phpt @@ -0,0 +1,97 @@ +--TEST-- +SPL: CachingIterator and __toString() +--SKIPIF-- + +--FILE-- +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=== + +--EXPECT-- +01234123, Joe +00000014, Bob +===DONE===