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