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