map.c 18 KB

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