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