Skip to content

Commit 9658d9a

Browse files
ju1iusGirgias
authored andcommitted
adds failing test case for #12060
Signed-off-by: George Peter Banyard <girgias@php.net>
1 parent f1f608b commit 9658d9a

File tree

8 files changed

+231
-2
lines changed

8 files changed

+231
-2
lines changed

ext/zend_test/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
44
[Enable zend_test extension])])
55

66
if test "$PHP_ZEND_TEST" != "no"; then
7-
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
7+
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
88
fi

ext/zend_test/config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
44

55
if (PHP_ZEND_TEST != "no") {
6-
EXTENSION("zend_test", "test.c observer.c fiber.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
6+
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
77
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
88
}

ext/zend_test/iterators.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| license@php.net so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
*/
14+
15+
#include "iterators.h"
16+
#include "zend_API.h"
17+
#include "iterators_arginfo.h"
18+
19+
#include <zend_interfaces.h>
20+
#include "php.h"
21+
22+
#define DUMP(s) php_output_write((s), sizeof((s)) - 1)
23+
24+
static zend_class_entry *traversable_test_ce;
25+
26+
// Dummy iterator that yields numbers from 0..4,
27+
// while printing operations to the output buffer
28+
typedef struct {
29+
zend_object_iterator intern;
30+
zval current;
31+
} test_traversable_it;
32+
33+
static test_traversable_it *test_traversable_it_fetch(zend_object_iterator *iter) {
34+
return (test_traversable_it *)iter;
35+
}
36+
37+
static void test_traversable_it_dtor(zend_object_iterator *iter) {
38+
DUMP("TraversableTest::drop\n");
39+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
40+
zval_ptr_dtor(&iterator->intern.data);
41+
}
42+
43+
static void test_traversable_it_rewind(zend_object_iterator *iter) {
44+
DUMP("TraversableTest::rewind\n");
45+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
46+
ZVAL_LONG(&iterator->current, 0);
47+
}
48+
49+
static void test_traversable_it_next(zend_object_iterator *iter) {
50+
DUMP("TraversableTest::next\n");
51+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
52+
ZVAL_LONG(&iterator->current, Z_LVAL(iterator->current) + 1);
53+
}
54+
55+
static int test_traversable_it_valid(zend_object_iterator *iter) {
56+
DUMP("TraversableTest::valid\n");
57+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
58+
if (Z_LVAL(iterator->current) < 4) {
59+
return SUCCESS;
60+
}
61+
return FAILURE;
62+
}
63+
64+
static void test_traversable_it_key(zend_object_iterator *iter, zval *return_value) {
65+
DUMP("TraversableTest::key\n");
66+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
67+
ZVAL_LONG(return_value, Z_LVAL(iterator->current));
68+
}
69+
70+
static zval *test_traversable_it_current(zend_object_iterator *iter) {
71+
DUMP("TraversableTest::current\n");
72+
test_traversable_it *iterator = test_traversable_it_fetch(iter);
73+
return &iterator->current;
74+
}
75+
76+
static const zend_object_iterator_funcs test_traversable_it_vtable = {
77+
test_traversable_it_dtor,
78+
test_traversable_it_valid,
79+
test_traversable_it_current,
80+
test_traversable_it_key,
81+
test_traversable_it_next,
82+
test_traversable_it_rewind,
83+
NULL, // invalidate_current
84+
NULL, // get_gc
85+
};
86+
87+
static zend_object_iterator *test_traversable_get_iterator(
88+
zend_class_entry *ce,
89+
zval *object,
90+
int by_ref
91+
) {
92+
test_traversable_it *iterator;
93+
94+
if (by_ref) {
95+
zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
96+
return NULL;
97+
}
98+
99+
iterator = emalloc(sizeof(test_traversable_it));
100+
zend_iterator_init((zend_object_iterator*)iterator);
101+
102+
ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
103+
iterator->intern.funcs = &test_traversable_it_vtable;
104+
ZVAL_LONG(&iterator->current, 0);
105+
106+
return (zend_object_iterator*)iterator;
107+
}
108+
109+
ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct) {
110+
ZEND_PARSE_PARAMETERS_NONE();
111+
}
112+
113+
ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator) {
114+
ZEND_PARSE_PARAMETERS_NONE();
115+
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
116+
}
117+
118+
void zend_test_iterators_init(void) {
119+
traversable_test_ce = register_class_ZendTest_Iterators_TraversableTest(zend_ce_aggregate);
120+
traversable_test_ce->get_iterator = test_traversable_get_iterator;
121+
}

ext/zend_test/iterators.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| license@php.net so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
*/
14+
15+
#ifndef ZEND_TEST_ITERATORS_H
16+
#define ZEND_TEST_ITERATORS_H
17+
18+
void zend_test_iterators_init(void);
19+
20+
#endif
21+

ext/zend_test/iterators.stub.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
/**
4+
* @generate-class-entries static
5+
* @undocumentable
6+
*/
7+
8+
namespace ZendTest\Iterators;
9+
10+
final class TraversableTest implements \IteratorAggregate
11+
{
12+
public function __construct() {}
13+
public function getIterator(): \Iterator {}
14+
}

ext/zend_test/iterators_arginfo.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* This is a generated file, edit the .stub.php file instead.
2+
* Stub hash: f9558686a7393ddd4ba3302e811f70d4496317ee */
3+
4+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest___construct, 0, 0, 0)
5+
ZEND_END_ARG_INFO()
6+
7+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, 0, 0, Iterator, 0)
8+
ZEND_END_ARG_INFO()
9+
10+
11+
static ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct);
12+
static ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator);
13+
14+
15+
static const zend_function_entry class_ZendTest_Iterators_TraversableTest_methods[] = {
16+
ZEND_ME(ZendTest_Iterators_TraversableTest, __construct, arginfo_class_ZendTest_Iterators_TraversableTest___construct, ZEND_ACC_PUBLIC)
17+
ZEND_ME(ZendTest_Iterators_TraversableTest, getIterator, arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, ZEND_ACC_PUBLIC)
18+
ZEND_FE_END
19+
};
20+
21+
static zend_class_entry *register_class_ZendTest_Iterators_TraversableTest(zend_class_entry *class_entry_IteratorAggregate)
22+
{
23+
zend_class_entry ce, *class_entry;
24+
25+
INIT_NS_CLASS_ENTRY(ce, "ZendTest\\Iterators", "TraversableTest", class_ZendTest_Iterators_TraversableTest_methods);
26+
class_entry = zend_register_internal_class_ex(&ce, NULL);
27+
class_entry->ce_flags |= ZEND_ACC_FINAL;
28+
zend_class_implements(class_entry, 1, class_entry_IteratorAggregate);
29+
30+
return class_entry;
31+
}

ext/zend_test/test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "php_test.h"
2525
#include "observer.h"
2626
#include "fiber.h"
27+
#include "iterators.h"
2728
#include "zend_attributes.h"
2829
#include "zend_enum.h"
2930
#include "zend_interfaces.h"
@@ -660,6 +661,7 @@ PHP_MINIT_FUNCTION(zend_test)
660661

661662
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
662663
zend_test_fiber_init();
664+
zend_test_iterators_init();
663665

664666
return SUCCESS;
665667
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Tests that internal iterator's rewind function is called once
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
$subject = new \ZendTest\Iterators\TraversableTest();
9+
$it = $subject->getIterator();
10+
var_dump($it);
11+
foreach ($it as $key => $value) {
12+
echo "{$key} => {$value}\n";
13+
}
14+
?>
15+
--EXPECT--
16+
object(InternalIterator)#3 (0) {
17+
}
18+
TraversableTest::rewind
19+
TraversableTest::valid
20+
TraversableTest::current
21+
TraversableTest::key
22+
0 => 0
23+
TraversableTest::next
24+
TraversableTest::valid
25+
TraversableTest::current
26+
TraversableTest::key
27+
1 => 1
28+
TraversableTest::next
29+
TraversableTest::valid
30+
TraversableTest::current
31+
TraversableTest::key
32+
2 => 2
33+
TraversableTest::next
34+
TraversableTest::valid
35+
TraversableTest::current
36+
TraversableTest::key
37+
3 => 3
38+
TraversableTest::next
39+
TraversableTest::valid
40+
TraversableTest::drop

0 commit comments

Comments
 (0)