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