1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "array.h"
9
10 #include <Zend/zend_API.h>
11 #include <Zend/zend_interfaces.h>
12
13 #include <ext/spl/spl_iterators.h>
14
15 // This is not self-contained: it must be after other Zend includes.
16 #include <Zend/zend_exceptions.h>
17
18 #include "arena.h"
19 #include "convert.h"
20 #include "def.h"
21 #include "message.h"
22 #include "php-upb.h"
23 #include "protobuf.h"
24
25 static void RepeatedFieldIter_make(zval* val, zval* repeated_field);
26
27 // -----------------------------------------------------------------------------
28 // RepeatedField
29 // -----------------------------------------------------------------------------
30
31 typedef struct {
32 zend_object std;
33 zval arena;
34 upb_Array* array;
35 TypeInfo type;
36 } RepeatedField;
37
38 zend_class_entry* RepeatedField_class_entry;
39 static zend_object_handlers RepeatedField_object_handlers;
40
41 // PHP Object Handlers /////////////////////////////////////////////////////////
42
43 /**
44 * RepeatedField_create()
45 *
46 * PHP class entry function to allocate and initialize a new RepeatedField
47 * object.
48 */
RepeatedField_create(zend_class_entry * class_type)49 static zend_object* RepeatedField_create(zend_class_entry* class_type) {
50 RepeatedField* intern = emalloc(sizeof(RepeatedField));
51 zend_object_std_init(&intern->std, class_type);
52 intern->std.handlers = &RepeatedField_object_handlers;
53 Arena_Init(&intern->arena);
54 intern->array = NULL;
55 // Skip object_properties_init(), we don't allow derived classes.
56 return &intern->std;
57 }
58
59 /**
60 * RepeatedField_dtor()
61 *
62 * Object handler to destroy a RepeatedField. This releases all resources
63 * associated with the message. Note that it is possible to access a destroyed
64 * object from PHP in rare cases.
65 */
RepeatedField_destructor(zend_object * obj)66 static void RepeatedField_destructor(zend_object* obj) {
67 RepeatedField* intern = (RepeatedField*)obj;
68 ObjCache_Delete(intern->array);
69 zval_ptr_dtor(&intern->arena);
70 zend_object_std_dtor(&intern->std);
71 }
72
73 /**
74 * RepeatedField_compare_objects()
75 *
76 * Object handler for comparing two repeated field objects. Called whenever PHP
77 * code does:
78 *
79 * $rf1 == $rf2
80 */
RepeatedField_compare_objects(zval * rf1,zval * rf2)81 static int RepeatedField_compare_objects(zval* rf1, zval* rf2) {
82 RepeatedField* intern1 = (RepeatedField*)Z_OBJ_P(rf1);
83 RepeatedField* intern2 = (RepeatedField*)Z_OBJ_P(rf2);
84
85 return TypeInfo_Eq(intern1->type, intern2->type) &&
86 ArrayEq(intern1->array, intern2->array, intern1->type)
87 ? 0
88 : 1;
89 }
90
91 /**
92 * RepeatedField_clone_obj()
93 *
94 * Object handler for cloning an object in PHP. Called when PHP code does:
95 *
96 * $rf2 = clone $rf1;
97 */
RepeatedField_clone_obj(zend_object * object)98 static zend_object* RepeatedField_clone_obj(zend_object* object) {
99 RepeatedField* intern = (RepeatedField*)object;
100 upb_Arena* arena = Arena_Get(&intern->arena);
101 upb_Array* clone = upb_Array_New(arena, intern->type.type);
102 size_t n = upb_Array_Size(intern->array);
103 size_t i;
104
105 for (i = 0; i < n; i++) {
106 upb_MessageValue msgval = upb_Array_Get(intern->array, i);
107 upb_Array_Append(clone, msgval, arena);
108 }
109
110 zval ret;
111 RepeatedField_GetPhpWrapper(&ret, clone, intern->type, &intern->arena);
112 return Z_OBJ_P(&ret);
113 }
114
RepeatedField_GetProperties(zend_object * object)115 static HashTable* RepeatedField_GetProperties(zend_object* object) {
116 return NULL; // We do not have a properties table.
117 }
118
RepeatedField_GetPropertyPtrPtr(zend_object * object,zend_string * member,int type,void ** cache_slot)119 static zval* RepeatedField_GetPropertyPtrPtr(zend_object* object,
120 zend_string* member, int type,
121 void** cache_slot) {
122 return NULL; // We don't offer direct references to our properties.
123 }
124
125 // C Functions from array.h ////////////////////////////////////////////////////
126
127 // These are documented in the header file.
128
RepeatedField_GetPhpWrapper(zval * val,upb_Array * arr,TypeInfo type,zval * arena)129 void RepeatedField_GetPhpWrapper(zval* val, upb_Array* arr, TypeInfo type,
130 zval* arena) {
131 if (!arr) {
132 ZVAL_NULL(val);
133 return;
134 }
135
136 if (!ObjCache_Get(arr, val)) {
137 RepeatedField* intern = emalloc(sizeof(RepeatedField));
138 zend_object_std_init(&intern->std, RepeatedField_class_entry);
139 intern->std.handlers = &RepeatedField_object_handlers;
140 ZVAL_COPY(&intern->arena, arena);
141 intern->array = arr;
142 intern->type = type;
143 // Skip object_properties_init(), we don't allow derived classes.
144 ObjCache_Add(intern->array, &intern->std);
145 ZVAL_OBJ(val, &intern->std);
146 }
147 }
148
RepeatedField_GetUpbArray(zval * val,TypeInfo type,upb_Arena * arena)149 upb_Array* RepeatedField_GetUpbArray(zval* val, TypeInfo type,
150 upb_Arena* arena) {
151 if (Z_ISREF_P(val)) {
152 ZVAL_DEREF(val);
153 }
154
155 if (Z_TYPE_P(val) == IS_ARRAY) {
156 // Auto-construct, eg. [1, 2, 3] -> upb_Array([1, 2, 3]).
157 upb_Array* arr = upb_Array_New(arena, type.type);
158 HashTable* table = HASH_OF(val);
159 HashPosition pos;
160
161 zend_hash_internal_pointer_reset_ex(table, &pos);
162
163 while (true) {
164 zval* zv = zend_hash_get_current_data_ex(table, &pos);
165 upb_MessageValue val;
166
167 if (!zv) return arr;
168
169 if (!Convert_PhpToUpbAutoWrap(zv, &val, type, arena)) {
170 return NULL;
171 }
172
173 upb_Array_Append(arr, val, arena);
174 zend_hash_move_forward_ex(table, &pos);
175 }
176 } else if (Z_TYPE_P(val) == IS_OBJECT &&
177 Z_OBJCE_P(val) == RepeatedField_class_entry) {
178 // Unwrap existing RepeatedField object to get the upb_Array* inside.
179 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(val);
180
181 if (!TypeInfo_Eq(intern->type, type)) {
182 php_error_docref(NULL, E_USER_ERROR,
183 "Wrong type for this repeated field.");
184 }
185
186 upb_Arena_Fuse(arena, Arena_Get(&intern->arena));
187 return intern->array;
188 } else {
189 php_error_docref(NULL, E_USER_ERROR, "Must be a repeated field");
190 return NULL;
191 }
192 }
193
ArrayEq(const upb_Array * a1,const upb_Array * a2,TypeInfo type)194 bool ArrayEq(const upb_Array* a1, const upb_Array* a2, TypeInfo type) {
195 size_t i;
196 size_t n;
197
198 if ((a1 == NULL) != (a2 == NULL)) return false;
199 if (a1 == NULL) return true;
200
201 n = upb_Array_Size(a1);
202 if (n != upb_Array_Size(a2)) return false;
203
204 for (i = 0; i < n; i++) {
205 upb_MessageValue val1 = upb_Array_Get(a1, i);
206 upb_MessageValue val2 = upb_Array_Get(a2, i);
207 if (!ValueEq(val1, val2, type)) return false;
208 }
209
210 return true;
211 }
212
213 // RepeatedField PHP methods ///////////////////////////////////////////////////
214
215 /**
216 * RepeatedField::__construct()
217 *
218 * Constructs an instance of RepeatedField.
219 * @param long Type of the stored element.
220 * @param string Message/Enum class.
221 */
PHP_METHOD(RepeatedField,__construct)222 PHP_METHOD(RepeatedField, __construct) {
223 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
224 upb_Arena* arena = Arena_Get(&intern->arena);
225 zend_long type;
226 zend_class_entry* klass = NULL;
227
228 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|C", &type, &klass) != SUCCESS) {
229 return;
230 }
231
232 intern->type.type = pbphp_dtype_to_type(type);
233 intern->type.desc = Descriptor_GetFromClassEntry(klass);
234
235 if (intern->type.type == kUpb_CType_Message && klass == NULL) {
236 php_error_docref(NULL, E_USER_ERROR,
237 "Message/enum type must have concrete class.");
238 return;
239 }
240
241 intern->array = upb_Array_New(arena, intern->type.type);
242 ObjCache_Add(intern->array, &intern->std);
243 }
244
245 /**
246 * RepeatedField::append()
247 *
248 * Append element to the end of the repeated field.
249 * @param object The element to be added.
250 */
PHP_METHOD(RepeatedField,append)251 PHP_METHOD(RepeatedField, append) {
252 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
253 upb_Arena* arena = Arena_Get(&intern->arena);
254 zval* php_val;
255 upb_MessageValue msgval;
256
257 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &php_val) != SUCCESS ||
258 !Convert_PhpToUpb(php_val, &msgval, intern->type, arena)) {
259 return;
260 }
261
262 upb_Array_Append(intern->array, msgval, arena);
263 }
264
265 /**
266 * RepeatedField::offsetExists(): bool
267 *
268 * Implements the ArrayAccess interface. Invoked when PHP code calls:
269 *
270 * isset($arr[$idx]);
271 * empty($arr[$idx]);
272 *
273 * @param long The index to be checked.
274 * @return bool True if the element at the given index exists.
275 */
PHP_METHOD(RepeatedField,offsetExists)276 PHP_METHOD(RepeatedField, offsetExists) {
277 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
278 zend_long index;
279
280 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
281 return;
282 }
283
284 RETURN_BOOL(index >= 0 && index < upb_Array_Size(intern->array));
285 }
286
287 /**
288 * RepeatedField::offsetGet(): mixed
289 *
290 * Implements the ArrayAccess interface. Invoked when PHP code calls:
291 *
292 * $x = $arr[$idx];
293 *
294 * @param long The index of the element to be fetched.
295 * @return object The stored element at given index.
296 * @exception Invalid type for index.
297 * @exception Non-existing index.
298 */
PHP_METHOD(RepeatedField,offsetGet)299 PHP_METHOD(RepeatedField, offsetGet) {
300 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
301 zend_long index;
302 upb_MessageValue msgval;
303 zval ret;
304
305 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
306 return;
307 }
308
309 if (index < 0 || index >= upb_Array_Size(intern->array)) {
310 zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
311 return;
312 }
313
314 msgval = upb_Array_Get(intern->array, index);
315 Convert_UpbToPhp(msgval, &ret, intern->type, &intern->arena);
316 RETURN_COPY_VALUE(&ret);
317 }
318
319 /**
320 * RepeatedField::offsetSet(): void
321 *
322 * Implements the ArrayAccess interface. Invoked when PHP code calls:
323 *
324 * $arr[$idx] = $x;
325 * $arr []= $x; // Append
326 *
327 * @param long The index of the element to be assigned.
328 * @param object The element to be assigned.
329 * @exception Invalid type for index.
330 * @exception Non-existing index.
331 * @exception Incorrect type of the element.
332 */
PHP_METHOD(RepeatedField,offsetSet)333 PHP_METHOD(RepeatedField, offsetSet) {
334 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
335 upb_Arena* arena = Arena_Get(&intern->arena);
336 size_t size = upb_Array_Size(intern->array);
337 zval *offset, *val;
338 int64_t index;
339 upb_MessageValue msgval;
340
341 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &offset, &val) != SUCCESS) {
342 return;
343 }
344
345 if (Z_TYPE_P(offset) == IS_NULL) {
346 index = size;
347 } else if (!Convert_PhpToInt64(offset, &index)) {
348 return;
349 }
350
351 if (!Convert_PhpToUpb(val, &msgval, intern->type, arena)) {
352 return;
353 }
354
355 if (index > size) {
356 zend_error(E_USER_ERROR, "Element at index %ld doesn't exist.\n", index);
357 } else if (index == size) {
358 upb_Array_Append(intern->array, msgval, Arena_Get(&intern->arena));
359 } else {
360 upb_Array_Set(intern->array, index, msgval);
361 }
362 }
363
364 /**
365 * RepeatedField::offsetUnset(): void
366 *
367 * Implements the ArrayAccess interface. Invoked when PHP code calls:
368 *
369 * unset($arr[$idx]);
370 *
371 * @param long The index of the element to be removed.
372 * @exception Invalid type for index.
373 * @exception The element to be removed is not at the end of the RepeatedField.
374 */
PHP_METHOD(RepeatedField,offsetUnset)375 PHP_METHOD(RepeatedField, offsetUnset) {
376 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
377 zend_long index;
378 zend_long size = upb_Array_Size(intern->array);
379
380 // Only the element at the end of the array can be removed.
381 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) != SUCCESS) {
382 return;
383 }
384
385 if (size == 0 || index < 0 || index >= size) {
386 php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n",
387 index);
388 return;
389 }
390
391 upb_Array_Delete(intern->array, index, 1);
392 }
393
394 /**
395 * RepeatedField::count(): int
396 *
397 * Implements the Countable interface. Invoked when PHP code calls:
398 *
399 * $len = count($arr);
400 * Return the number of stored elements.
401 * This will also be called for: count($arr)
402 * @return long The number of stored elements.
403 */
PHP_METHOD(RepeatedField,count)404 PHP_METHOD(RepeatedField, count) {
405 RepeatedField* intern = (RepeatedField*)Z_OBJ_P(getThis());
406
407 if (zend_parse_parameters_none() == FAILURE) {
408 return;
409 }
410
411 RETURN_LONG(upb_Array_Size(intern->array));
412 }
413
414 /**
415 * RepeatedField::getIterator(): Traversable
416 *
417 * Implements the IteratorAggregate interface. Invoked when PHP code calls:
418 *
419 * foreach ($arr) {}
420 *
421 * @return object Beginning iterator.
422 */
PHP_METHOD(RepeatedField,getIterator)423 PHP_METHOD(RepeatedField, getIterator) {
424 zval ret;
425 RepeatedFieldIter_make(&ret, getThis());
426 RETURN_COPY_VALUE(&ret);
427 }
428
429 // clang-format off
430 ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1)
431 ZEND_ARG_INFO(0, type)
432 ZEND_ARG_INFO(0, class)
433 ZEND_END_ARG_INFO()
434
435 ZEND_BEGIN_ARG_INFO_EX(arginfo_append, 0, 0, 1)
436 ZEND_ARG_INFO(0, newval)
437 ZEND_END_ARG_INFO()
438
439 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetExists, 0, 0, _IS_BOOL, 0)
440 ZEND_ARG_INFO(0, index)
441 ZEND_END_ARG_INFO()
442
443 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_offsetGet, 0, 0, IS_MIXED, 1)
444 ZEND_ARG_INFO(0, index)
445 ZEND_END_ARG_INFO()
446
447 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetSet, 0, 2, IS_VOID, 0)
448 ZEND_ARG_INFO(0, index)
449 ZEND_ARG_INFO(0, newval)
450 ZEND_END_ARG_INFO()
451
452 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetUnset, 0, 0, IS_VOID, 0)
453 ZEND_ARG_INFO(0, index)
454 ZEND_END_ARG_INFO()
455
456 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_count, 0, 0, IS_LONG, 0)
457 ZEND_END_ARG_INFO()
458
459 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_getIterator, 0, 0, Traversable, 0)
460 ZEND_END_ARG_INFO()
461
462 static zend_function_entry repeated_field_methods[] = {
463 PHP_ME(RepeatedField, __construct, arginfo_construct, ZEND_ACC_PUBLIC)
464 PHP_ME(RepeatedField, append, arginfo_append, ZEND_ACC_PUBLIC)
465 PHP_ME(RepeatedField, offsetExists, arginfo_offsetExists, ZEND_ACC_PUBLIC)
466 PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC)
467 PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
468 PHP_ME(RepeatedField, offsetUnset, arginfo_offsetUnset, ZEND_ACC_PUBLIC)
469 PHP_ME(RepeatedField, count, arginfo_count, ZEND_ACC_PUBLIC)
470 PHP_ME(RepeatedField, getIterator, arginfo_getIterator, ZEND_ACC_PUBLIC)
471 ZEND_FE_END
472 };
473 // clang-format on
474
475 // -----------------------------------------------------------------------------
476 // PHP RepeatedFieldIter
477 // -----------------------------------------------------------------------------
478
479 typedef struct {
480 zend_object std;
481 zval repeated_field;
482 zend_long position;
483 } RepeatedFieldIter;
484
485 zend_class_entry* RepeatedFieldIter_class_entry;
486 static zend_object_handlers repeated_field_iter_object_handlers;
487
488 /**
489 * RepeatedFieldIter_create()
490 *
491 * PHP class entry function to allocate and initialize a new RepeatedFieldIter
492 * object.
493 */
RepeatedFieldIter_create(zend_class_entry * class_type)494 zend_object* RepeatedFieldIter_create(zend_class_entry* class_type) {
495 RepeatedFieldIter* intern = emalloc(sizeof(RepeatedFieldIter));
496 zend_object_std_init(&intern->std, class_type);
497 intern->std.handlers = &repeated_field_iter_object_handlers;
498 ZVAL_NULL(&intern->repeated_field);
499 intern->position = 0;
500 // Skip object_properties_init(), we don't allow derived classes.
501 return &intern->std;
502 }
503
504 /**
505 * RepeatedFieldIter_dtor()
506 *
507 * Object handler to destroy a RepeatedFieldIter. This releases all resources
508 * associated with the message. Note that it is possible to access a destroyed
509 * object from PHP in rare cases.
510 */
RepeatedFieldIter_dtor(zend_object * obj)511 static void RepeatedFieldIter_dtor(zend_object* obj) {
512 RepeatedFieldIter* intern = (RepeatedFieldIter*)obj;
513 zval_ptr_dtor(&intern->repeated_field);
514 zend_object_std_dtor(&intern->std);
515 }
516
517 /**
518 * RepeatedFieldIter_make()
519 *
520 * C function to create a RepeatedFieldIter.
521 */
RepeatedFieldIter_make(zval * val,zval * repeated_field)522 static void RepeatedFieldIter_make(zval* val, zval* repeated_field) {
523 RepeatedFieldIter* iter;
524 ZVAL_OBJ(val, RepeatedFieldIter_class_entry->create_object(
525 RepeatedFieldIter_class_entry));
526 iter = (RepeatedFieldIter*)Z_OBJ_P(val);
527 ZVAL_COPY(&iter->repeated_field, repeated_field);
528 }
529
530 /*
531 * When a user writes:
532 *
533 * foreach($arr as $key => $val) {}
534 *
535 * PHP's iterator protocol is:
536 *
537 * $iter = $arr->getIterator();
538 * for ($iter->rewind(); $iter->valid(); $iter->next()) {
539 * $key = $iter->key();
540 * $val = $iter->current();
541 * }
542 */
543
544 /**
545 * RepeatedFieldIter::rewind(): void
546 *
547 * Implements the Iterator interface. Sets the iterator to the first element.
548 */
PHP_METHOD(RepeatedFieldIter,rewind)549 PHP_METHOD(RepeatedFieldIter, rewind) {
550 RepeatedFieldIter* intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
551 intern->position = 0;
552 }
553
554 /**
555 * RepeatedFieldIter::current(): mixed
556 *
557 * Implements the Iterator interface. Returns the current value.
558 */
PHP_METHOD(RepeatedFieldIter,current)559 PHP_METHOD(RepeatedFieldIter, current) {
560 RepeatedFieldIter* intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
561 RepeatedField* field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field);
562 upb_Array* array = field->array;
563 zend_long index = intern->position;
564 upb_MessageValue msgval;
565 zval ret;
566
567 if (index < 0 || index >= upb_Array_Size(array)) {
568 zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
569 }
570
571 msgval = upb_Array_Get(array, index);
572
573 Convert_UpbToPhp(msgval, &ret, field->type, &field->arena);
574 RETURN_COPY_VALUE(&ret);
575 }
576
577 /**
578 * RepeatedFieldIter::key(): mixed
579 *
580 * Implements the Iterator interface. Returns the current key.
581 */
PHP_METHOD(RepeatedFieldIter,key)582 PHP_METHOD(RepeatedFieldIter, key) {
583 RepeatedFieldIter* intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
584 RETURN_LONG(intern->position);
585 }
586
587 /**
588 * RepeatedFieldIter::next(): void
589 *
590 * Implements the Iterator interface. Advances to the next element.
591 */
PHP_METHOD(RepeatedFieldIter,next)592 PHP_METHOD(RepeatedFieldIter, next) {
593 RepeatedFieldIter* intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
594 ++intern->position;
595 }
596
597 /**
598 * RepeatedFieldIter::valid(): bool
599 *
600 * Implements the Iterator interface. Returns true if this is a valid element.
601 */
PHP_METHOD(RepeatedFieldIter,valid)602 PHP_METHOD(RepeatedFieldIter, valid) {
603 RepeatedFieldIter* intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
604 RepeatedField* field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field);
605 RETURN_BOOL(intern->position < upb_Array_Size(field->array));
606 }
607
608 // clang-format: off
609 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_current, 0, 0,
610 IS_MIXED, 0)
611 ZEND_END_ARG_INFO()
612
613 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_key, 0, 0, IS_MIXED,
614 0)
615 ZEND_END_ARG_INFO()
616
617 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_next, 0, 0, IS_VOID, 0)
618 ZEND_END_ARG_INFO()
619
620 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_valid, 0, 0, _IS_BOOL, 0)
621 ZEND_END_ARG_INFO()
622
623 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rewind, 0, 0, IS_VOID, 0)
624 ZEND_END_ARG_INFO()
625
626 static zend_function_entry repeated_field_iter_methods[] = {
627 PHP_ME(RepeatedFieldIter, rewind, arginfo_rewind, ZEND_ACC_PUBLIC)
628 PHP_ME(RepeatedFieldIter, current, arginfo_current, ZEND_ACC_PUBLIC)
629 PHP_ME(RepeatedFieldIter, key, arginfo_key, ZEND_ACC_PUBLIC) PHP_ME(
630 RepeatedFieldIter, next, arginfo_next, ZEND_ACC_PUBLIC)
631 PHP_ME(RepeatedFieldIter, valid, arginfo_valid, ZEND_ACC_PUBLIC)
632 ZEND_FE_END};
633 // clang-format: on
634
635 // -----------------------------------------------------------------------------
636 // Module init.
637 // -----------------------------------------------------------------------------
638
639 /**
640 * Array_ModuleInit()
641 *
642 * Called when the C extension is loaded to register all types.
643 */
Array_ModuleInit()644 void Array_ModuleInit() {
645 zend_class_entry tmp_ce;
646 zend_object_handlers* h;
647
648 // RepeatedField.
649 INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedField",
650 repeated_field_methods);
651
652 RepeatedField_class_entry = zend_register_internal_class(&tmp_ce);
653 zend_class_implements(RepeatedField_class_entry, 3, zend_ce_arrayaccess,
654 zend_ce_aggregate, zend_ce_countable);
655 RepeatedField_class_entry->ce_flags |= ZEND_ACC_FINAL;
656 RepeatedField_class_entry->create_object = RepeatedField_create;
657
658 h = &RepeatedField_object_handlers;
659 memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
660 h->dtor_obj = RepeatedField_destructor;
661 h->compare = RepeatedField_compare_objects;
662 h->clone_obj = RepeatedField_clone_obj;
663 h->get_properties = RepeatedField_GetProperties;
664 h->get_property_ptr_ptr = RepeatedField_GetPropertyPtrPtr;
665
666 // RepeatedFieldIter
667 INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedFieldIter",
668 repeated_field_iter_methods);
669
670 RepeatedFieldIter_class_entry = zend_register_internal_class(&tmp_ce);
671 zend_class_implements(RepeatedFieldIter_class_entry, 1, zend_ce_iterator);
672 RepeatedFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL;
673 RepeatedFieldIter_class_entry->create_object = RepeatedFieldIter_create;
674
675 h = &repeated_field_iter_object_handlers;
676 memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
677 h->dtor_obj = RepeatedFieldIter_dtor;
678 }
679