array.c 20 KB

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