xref: /php-src/ext/zend_test/iterators.c (revision 97267215)
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 
test_traversable_it_fetch(zend_object_iterator * iter)33 static test_traversable_it *test_traversable_it_fetch(zend_object_iterator *iter) {
34 	return (test_traversable_it *)iter;
35 }
36 
test_traversable_it_dtor(zend_object_iterator * iter)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 
test_traversable_it_rewind(zend_object_iterator * iter)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 
test_traversable_it_next(zend_object_iterator * iter)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 
test_traversable_it_valid(zend_object_iterator * iter)55 static zend_result 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 
test_traversable_it_key(zend_object_iterator * iter,zval * return_value)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 
test_traversable_it_current(zend_object_iterator * iter)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 
test_traversable_get_iterator(zend_class_entry * ce,zval * object,int by_ref)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 
ZEND_METHOD(ZendTest_Iterators_TraversableTest,__construct)109 ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct) {
110 	ZEND_PARSE_PARAMETERS_NONE();
111 }
112 
ZEND_METHOD(ZendTest_Iterators_TraversableTest,getIterator)113 ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator) {
114 	ZEND_PARSE_PARAMETERS_NONE();
115     zend_create_internal_iterator_zval(return_value, ZEND_THIS);
116 }
117 
zend_test_iterators_init(void)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 }
122