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