array.c 19 KB

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