]> granicus.if.org Git - php/commitdiff
Fix CachingIterator's ability to cache string conversion results.
authorMarcus Boerger <helly@php.net>
Wed, 17 Mar 2004 19:58:32 +0000 (19:58 +0000)
committerMarcus Boerger <helly@php.net>
Wed, 17 Mar 2004 19:58:32 +0000 (19:58 +0000)
Add a test for that.

ext/spl/spl_iterators.c
ext/spl/tests/caching_iterator_str.phpt [new file with mode: 0755]

index 143ff9f6b6876d8912077db46d2566009cc35773..59cfd3b00cb2f394f14374877c41bda469993b1b 100755 (executable)
@@ -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 (executable)
index 0000000..c60776c
--- /dev/null
@@ -0,0 +1,97 @@
+--TEST--
+SPL: CachingIterator and __toString()
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--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===