zend_interfaces.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Marcus Boerger <helly@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "zend.h"
  19. #include "zend_API.h"
  20. #include "zend_interfaces.h"
  21. #include "zend_exceptions.h"
  22. #include "zend_interfaces_arginfo.h"
  23. ZEND_API zend_class_entry *zend_ce_traversable;
  24. ZEND_API zend_class_entry *zend_ce_aggregate;
  25. ZEND_API zend_class_entry *zend_ce_iterator;
  26. ZEND_API zend_class_entry *zend_ce_arrayaccess;
  27. ZEND_API zend_class_entry *zend_ce_serializable;
  28. ZEND_API zend_class_entry *zend_ce_countable;
  29. ZEND_API zend_class_entry *zend_ce_stringable;
  30. ZEND_API zend_class_entry *zend_ce_internal_iterator;
  31. static zend_object_handlers zend_internal_iterator_handlers;
  32. /* {{{ zend_call_method
  33. Only returns the returned zval if retval_ptr != NULL */
  34. ZEND_API zval* zend_call_method(zend_object *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, uint32_t param_count, zval* arg1, zval* arg2)
  35. {
  36. zend_function *fn;
  37. zend_class_entry *called_scope;
  38. zval params[2];
  39. if (param_count > 0) {
  40. ZVAL_COPY_VALUE(&params[0], arg1);
  41. }
  42. if (param_count > 1) {
  43. ZVAL_COPY_VALUE(&params[1], arg2);
  44. }
  45. if (!obj_ce) {
  46. obj_ce = object ? object->ce : NULL;
  47. }
  48. if (!fn_proxy || !*fn_proxy) {
  49. if (EXPECTED(obj_ce)) {
  50. fn = zend_hash_str_find_ptr_lc(
  51. &obj_ce->function_table, function_name, function_name_len);
  52. if (UNEXPECTED(fn == NULL)) {
  53. /* error at c-level */
  54. zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s::%s", ZSTR_VAL(obj_ce->name), function_name);
  55. }
  56. } else {
  57. fn = zend_fetch_function_str(function_name, function_name_len);
  58. if (UNEXPECTED(fn == NULL)) {
  59. /* error at c-level */
  60. zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for function %s", function_name);
  61. }
  62. }
  63. if (fn_proxy) {
  64. *fn_proxy = fn;
  65. }
  66. } else {
  67. fn = *fn_proxy;
  68. }
  69. if (object) {
  70. called_scope = object->ce;
  71. } else {
  72. called_scope = obj_ce;
  73. }
  74. zend_call_known_function(fn, object, called_scope, retval_ptr, param_count, params, NULL);
  75. return retval_ptr;
  76. }
  77. /* }}} */
  78. /* iterator interface, c-level functions used by engine */
  79. /* {{{ zend_user_it_new_iterator */
  80. ZEND_API void zend_user_it_new_iterator(zend_class_entry *ce, zval *object, zval *retval)
  81. {
  82. zend_call_known_instance_method_with_0_params(
  83. ce->iterator_funcs_ptr->zf_new_iterator, Z_OBJ_P(object), retval);
  84. }
  85. /* }}} */
  86. /* {{{ zend_user_it_invalidate_current */
  87. ZEND_API void zend_user_it_invalidate_current(zend_object_iterator *_iter)
  88. {
  89. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  90. if (!Z_ISUNDEF(iter->value)) {
  91. zval_ptr_dtor(&iter->value);
  92. ZVAL_UNDEF(&iter->value);
  93. }
  94. }
  95. /* }}} */
  96. /* {{{ zend_user_it_dtor */
  97. static void zend_user_it_dtor(zend_object_iterator *_iter)
  98. {
  99. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  100. zval *object = &iter->it.data;
  101. zend_user_it_invalidate_current(_iter);
  102. zval_ptr_dtor(object);
  103. }
  104. /* }}} */
  105. /* {{{ zend_user_it_valid */
  106. ZEND_API int zend_user_it_valid(zend_object_iterator *_iter)
  107. {
  108. if (_iter) {
  109. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  110. zval *object = &iter->it.data;
  111. zval more;
  112. bool result;
  113. zend_call_method_with_0_params(Z_OBJ_P(object), iter->ce, &iter->ce->iterator_funcs_ptr->zf_valid, "valid", &more);
  114. result = i_zend_is_true(&more);
  115. zval_ptr_dtor(&more);
  116. return result ? SUCCESS : FAILURE;
  117. }
  118. return FAILURE;
  119. }
  120. /* }}} */
  121. /* {{{ zend_user_it_get_current_data */
  122. ZEND_API zval *zend_user_it_get_current_data(zend_object_iterator *_iter)
  123. {
  124. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  125. zval *object = &iter->it.data;
  126. if (Z_ISUNDEF(iter->value)) {
  127. zend_call_method_with_0_params(Z_OBJ_P(object), iter->ce, &iter->ce->iterator_funcs_ptr->zf_current, "current", &iter->value);
  128. }
  129. return &iter->value;
  130. }
  131. /* }}} */
  132. /* {{{ zend_user_it_get_current_key */
  133. ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key)
  134. {
  135. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  136. zval *object = &iter->it.data;
  137. zend_call_method_with_0_params(Z_OBJ_P(object), iter->ce, &iter->ce->iterator_funcs_ptr->zf_key, "key", key);
  138. if (UNEXPECTED(Z_ISREF_P(key))) {
  139. zend_unwrap_reference(key);
  140. }
  141. }
  142. /* }}} */
  143. /* {{{ zend_user_it_move_forward */
  144. ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter)
  145. {
  146. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  147. zval *object = &iter->it.data;
  148. zend_user_it_invalidate_current(_iter);
  149. zend_call_method_with_0_params(Z_OBJ_P(object), iter->ce, &iter->ce->iterator_funcs_ptr->zf_next, "next", NULL);
  150. }
  151. /* }}} */
  152. /* {{{ zend_user_it_rewind */
  153. ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter)
  154. {
  155. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  156. zval *object = &iter->it.data;
  157. zend_user_it_invalidate_current(_iter);
  158. zend_call_method_with_0_params(Z_OBJ_P(object), iter->ce, &iter->ce->iterator_funcs_ptr->zf_rewind, "rewind", NULL);
  159. }
  160. /* }}} */
  161. ZEND_API HashTable *zend_user_it_get_gc(zend_object_iterator *_iter, zval **table, int *n)
  162. {
  163. zend_user_iterator *iter = (zend_user_iterator*)_iter;
  164. if (Z_ISUNDEF(iter->value)) {
  165. *table = &iter->it.data;
  166. *n = 1;
  167. } else {
  168. zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
  169. zend_get_gc_buffer_add_zval(gc_buffer, &iter->it.data);
  170. zend_get_gc_buffer_add_zval(gc_buffer, &iter->value);
  171. zend_get_gc_buffer_use(gc_buffer, table, n);
  172. }
  173. return NULL;
  174. }
  175. static const zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = {
  176. zend_user_it_dtor,
  177. zend_user_it_valid,
  178. zend_user_it_get_current_data,
  179. zend_user_it_get_current_key,
  180. zend_user_it_move_forward,
  181. zend_user_it_rewind,
  182. zend_user_it_invalidate_current,
  183. zend_user_it_get_gc,
  184. };
  185. /* {{{ zend_user_it_get_iterator */
  186. /* by_ref is int due to Iterator API */
  187. static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
  188. {
  189. zend_user_iterator *iterator;
  190. if (by_ref) {
  191. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  192. return NULL;
  193. }
  194. iterator = emalloc(sizeof(zend_user_iterator));
  195. zend_iterator_init((zend_object_iterator*)iterator);
  196. ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
  197. iterator->it.funcs = &zend_interface_iterator_funcs_iterator;
  198. iterator->ce = Z_OBJCE_P(object);
  199. ZVAL_UNDEF(&iterator->value);
  200. return (zend_object_iterator*)iterator;
  201. }
  202. /* }}} */
  203. /* {{{ zend_user_it_get_new_iterator */
  204. /* by_ref is int due to Iterator API */
  205. ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref)
  206. {
  207. zval iterator;
  208. zend_object_iterator *new_iterator;
  209. zend_class_entry *ce_it;
  210. zend_user_it_new_iterator(ce, object, &iterator);
  211. ce_it = (Z_TYPE(iterator) == IS_OBJECT) ? Z_OBJCE(iterator) : NULL;
  212. if (!ce_it || !ce_it->get_iterator || (ce_it->get_iterator == zend_user_it_get_new_iterator && Z_OBJ(iterator) == Z_OBJ_P(object))) {
  213. if (!EG(exception)) {
  214. zend_throw_exception_ex(NULL, 0, "Objects returned by %s::getIterator() must be traversable or implement interface Iterator", ce ? ZSTR_VAL(ce->name) : ZSTR_VAL(Z_OBJCE_P(object)->name));
  215. }
  216. zval_ptr_dtor(&iterator);
  217. return NULL;
  218. }
  219. new_iterator = ce_it->get_iterator(ce_it, &iterator, by_ref);
  220. zval_ptr_dtor(&iterator);
  221. return new_iterator;
  222. }
  223. /* }}} */
  224. /* {{{ zend_implement_traversable */
  225. static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type)
  226. {
  227. /* Abstract class can implement Traversable only, in which case the extending class must
  228. * implement Iterator or IteratorAggregate. */
  229. if (class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
  230. return SUCCESS;
  231. }
  232. /* Check that class_type implements at least one of 'IteratorAggregate' or 'Iterator' */
  233. if (class_type->num_interfaces) {
  234. ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
  235. for (uint32_t i = 0; i < class_type->num_interfaces; i++) {
  236. if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) {
  237. return SUCCESS;
  238. }
  239. }
  240. }
  241. zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s",
  242. ZSTR_VAL(class_type->name),
  243. ZSTR_VAL(zend_ce_traversable->name),
  244. ZSTR_VAL(zend_ce_iterator->name),
  245. ZSTR_VAL(zend_ce_aggregate->name));
  246. return FAILURE;
  247. }
  248. /* }}} */
  249. /* {{{ zend_implement_aggregate */
  250. static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type)
  251. {
  252. if (zend_class_implements_interface(class_type, zend_ce_iterator)) {
  253. zend_error_noreturn(E_ERROR,
  254. "Class %s cannot implement both Iterator and IteratorAggregate at the same time",
  255. ZSTR_VAL(class_type->name));
  256. }
  257. zend_function *zf = zend_hash_str_find_ptr(
  258. &class_type->function_table, "getiterator", sizeof("getiterator") - 1);
  259. if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_new_iterator) {
  260. /* get_iterator was explicitly assigned for an internal class. */
  261. if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) {
  262. ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS);
  263. return SUCCESS;
  264. }
  265. /* The getIterator() method has not been overwritten, use inherited get_iterator(). */
  266. if (zf->common.scope != class_type) {
  267. return SUCCESS;
  268. }
  269. /* getIterator() has been overwritten, switch to zend_user_it_get_new_iterator. */
  270. }
  271. ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?");
  272. zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS
  273. ? pemalloc(sizeof(zend_class_iterator_funcs), 1)
  274. : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
  275. class_type->get_iterator = zend_user_it_get_new_iterator;
  276. class_type->iterator_funcs_ptr = funcs_ptr;
  277. memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
  278. funcs_ptr->zf_new_iterator = zf;
  279. return SUCCESS;
  280. }
  281. /* }}} */
  282. /* {{{ zend_implement_iterator */
  283. static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type)
  284. {
  285. if (zend_class_implements_interface(class_type, zend_ce_aggregate)) {
  286. zend_error_noreturn(E_ERROR,
  287. "Class %s cannot implement both Iterator and IteratorAggregate at the same time",
  288. ZSTR_VAL(class_type->name));
  289. }
  290. if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) {
  291. if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) {
  292. /* get_iterator was explicitly assigned for an internal class. */
  293. ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS);
  294. return SUCCESS;
  295. }
  296. /* Otherwise get_iterator was inherited from the parent by default. */
  297. }
  298. if (class_type->parent && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) {
  299. /* Keep the inherited get_iterator handler. */
  300. class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR;
  301. } else {
  302. class_type->get_iterator = zend_user_it_get_iterator;
  303. }
  304. ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?");
  305. zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS
  306. ? pemalloc(sizeof(zend_class_iterator_funcs), 1)
  307. : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
  308. memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
  309. class_type->iterator_funcs_ptr = funcs_ptr;
  310. return SUCCESS;
  311. }
  312. /* }}} */
  313. /* {{{ zend_user_serialize */
  314. ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
  315. {
  316. zend_class_entry * ce = Z_OBJCE_P(object);
  317. zval retval;
  318. zend_result result;
  319. zend_call_method_with_0_params(
  320. Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "serialize", &retval);
  321. if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) {
  322. result = FAILURE;
  323. } else {
  324. switch(Z_TYPE(retval)) {
  325. case IS_NULL:
  326. /* we could also make this '*buf_len = 0' but this allows to skip variables */
  327. zval_ptr_dtor(&retval);
  328. return FAILURE;
  329. case IS_STRING:
  330. *buffer = (unsigned char*)estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
  331. *buf_len = Z_STRLEN(retval);
  332. result = SUCCESS;
  333. break;
  334. default: /* failure */
  335. result = FAILURE;
  336. break;
  337. }
  338. zval_ptr_dtor(&retval);
  339. }
  340. if (result == FAILURE && !EG(exception)) {
  341. zend_throw_exception_ex(NULL, 0, "%s::serialize() must return a string or NULL", ZSTR_VAL(ce->name));
  342. }
  343. return result;
  344. }
  345. /* }}} */
  346. /* {{{ zend_user_unserialize */
  347. ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
  348. {
  349. zval zdata;
  350. if (UNEXPECTED(object_init_ex(object, ce) != SUCCESS)) {
  351. return FAILURE;
  352. }
  353. ZVAL_STRINGL(&zdata, (char*)buf, buf_len);
  354. zend_call_method_with_1_params(
  355. Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "unserialize", NULL, &zdata);
  356. zval_ptr_dtor(&zdata);
  357. if (EG(exception)) {
  358. return FAILURE;
  359. } else {
  360. return SUCCESS;
  361. }
  362. }
  363. /* }}} */
  364. /* {{{ zend_implement_serializable */
  365. static int zend_implement_serializable(zend_class_entry *interface, zend_class_entry *class_type)
  366. {
  367. if (class_type->parent
  368. && (class_type->parent->serialize || class_type->parent->unserialize)
  369. && !zend_class_implements_interface(class_type->parent, zend_ce_serializable)) {
  370. return FAILURE;
  371. }
  372. if (!class_type->serialize) {
  373. class_type->serialize = zend_user_serialize;
  374. }
  375. if (!class_type->unserialize) {
  376. class_type->unserialize = zend_user_unserialize;
  377. }
  378. if (!(class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)
  379. && (!class_type->__serialize || !class_type->__unserialize)) {
  380. zend_error(E_DEPRECATED, "%s implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary)", ZSTR_VAL(class_type->name));
  381. }
  382. return SUCCESS;
  383. }
  384. /* }}}*/
  385. typedef struct {
  386. zend_object std;
  387. zend_object_iterator *iter;
  388. bool rewind_called;
  389. } zend_internal_iterator;
  390. static zend_object *zend_internal_iterator_create(zend_class_entry *ce) {
  391. zend_internal_iterator *intern = emalloc(sizeof(zend_internal_iterator));
  392. zend_object_std_init(&intern->std, ce);
  393. intern->std.handlers = &zend_internal_iterator_handlers;
  394. intern->iter = NULL;
  395. intern->rewind_called = 0;
  396. return &intern->std;
  397. }
  398. ZEND_API zend_result zend_create_internal_iterator_zval(zval *return_value, zval *obj) {
  399. zend_class_entry *scope = EG(current_execute_data)->func->common.scope;
  400. ZEND_ASSERT(scope->get_iterator != zend_user_it_get_new_iterator);
  401. zend_object_iterator *iter = scope->get_iterator(Z_OBJCE_P(obj), obj, /* by_ref */ 0);
  402. if (!iter) {
  403. return FAILURE;
  404. }
  405. zend_internal_iterator *intern =
  406. (zend_internal_iterator *) zend_internal_iterator_create(zend_ce_internal_iterator);
  407. intern->iter = iter;
  408. intern->iter->index = 0;
  409. ZVAL_OBJ(return_value, &intern->std);
  410. return SUCCESS;
  411. }
  412. static void zend_internal_iterator_free(zend_object *obj) {
  413. zend_internal_iterator *intern = (zend_internal_iterator *) obj;
  414. if (intern->iter) {
  415. zend_iterator_dtor(intern->iter);
  416. }
  417. zend_object_std_dtor(&intern->std);
  418. }
  419. static zend_internal_iterator *zend_internal_iterator_fetch(zval *This) {
  420. zend_internal_iterator *intern = (zend_internal_iterator *) Z_OBJ_P(This);
  421. if (!intern->iter) {
  422. zend_throw_error(NULL, "The InternalIterator object has not been properly initialized");
  423. return NULL;
  424. }
  425. return intern;
  426. }
  427. /* Many iterators will not behave correctly if rewind() is not called, make sure it happens. */
  428. static zend_result zend_internal_iterator_ensure_rewound(zend_internal_iterator *intern) {
  429. if (!intern->rewind_called) {
  430. zend_object_iterator *iter = intern->iter;
  431. intern->rewind_called = 1;
  432. if (iter->funcs->rewind) {
  433. iter->funcs->rewind(iter);
  434. if (UNEXPECTED(EG(exception))) {
  435. return FAILURE;
  436. }
  437. }
  438. }
  439. return SUCCESS;
  440. }
  441. ZEND_METHOD(InternalIterator, __construct) {
  442. zend_throw_error(NULL, "Cannot manually construct InternalIterator");
  443. }
  444. ZEND_METHOD(InternalIterator, current) {
  445. ZEND_PARSE_PARAMETERS_NONE();
  446. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  447. if (!intern) {
  448. RETURN_THROWS();
  449. }
  450. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  451. RETURN_THROWS();
  452. }
  453. zval *data = intern->iter->funcs->get_current_data(intern->iter);
  454. if (data) {
  455. RETURN_COPY_DEREF(data);
  456. }
  457. }
  458. ZEND_METHOD(InternalIterator, key) {
  459. ZEND_PARSE_PARAMETERS_NONE();
  460. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  461. if (!intern) {
  462. RETURN_THROWS();
  463. }
  464. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  465. RETURN_THROWS();
  466. }
  467. if (intern->iter->funcs->get_current_key) {
  468. intern->iter->funcs->get_current_key(intern->iter, return_value);
  469. } else {
  470. RETURN_LONG(intern->iter->index);
  471. }
  472. }
  473. ZEND_METHOD(InternalIterator, next) {
  474. ZEND_PARSE_PARAMETERS_NONE();
  475. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  476. if (!intern) {
  477. RETURN_THROWS();
  478. }
  479. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  480. RETURN_THROWS();
  481. }
  482. /* Advance index first to match foreach behavior. */
  483. intern->iter->index++;
  484. intern->iter->funcs->move_forward(intern->iter);
  485. }
  486. ZEND_METHOD(InternalIterator, valid) {
  487. ZEND_PARSE_PARAMETERS_NONE();
  488. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  489. if (!intern) {
  490. RETURN_THROWS();
  491. }
  492. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  493. RETURN_THROWS();
  494. }
  495. RETURN_BOOL(intern->iter->funcs->valid(intern->iter) == SUCCESS);
  496. }
  497. ZEND_METHOD(InternalIterator, rewind) {
  498. ZEND_PARSE_PARAMETERS_NONE();
  499. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  500. if (!intern) {
  501. RETURN_THROWS();
  502. }
  503. if (!intern->iter->funcs->rewind) {
  504. /* Allow calling rewind() if no iteration has happened yet,
  505. * even if the iterator does not support rewinding. */
  506. if (intern->iter->index != 0) {
  507. zend_throw_error(NULL, "Iterator does not support rewinding");
  508. RETURN_THROWS();
  509. }
  510. intern->iter->index = 0;
  511. return;
  512. }
  513. intern->iter->funcs->rewind(intern->iter);
  514. intern->iter->index = 0;
  515. }
  516. /* {{{ zend_register_interfaces */
  517. ZEND_API void zend_register_interfaces(void)
  518. {
  519. zend_ce_traversable = register_class_Traversable();
  520. zend_ce_traversable->interface_gets_implemented = zend_implement_traversable;
  521. zend_ce_aggregate = register_class_IteratorAggregate(zend_ce_traversable);
  522. zend_ce_aggregate->interface_gets_implemented = zend_implement_aggregate;
  523. zend_ce_iterator = register_class_Iterator(zend_ce_traversable);
  524. zend_ce_iterator->interface_gets_implemented = zend_implement_iterator;
  525. zend_ce_serializable = register_class_Serializable();
  526. zend_ce_serializable->interface_gets_implemented = zend_implement_serializable;
  527. zend_ce_arrayaccess = register_class_ArrayAccess();
  528. zend_ce_countable = register_class_Countable();
  529. zend_ce_stringable = register_class_Stringable();
  530. zend_ce_internal_iterator = register_class_InternalIterator(zend_ce_iterator);
  531. zend_ce_internal_iterator->create_object = zend_internal_iterator_create;
  532. memcpy(&zend_internal_iterator_handlers, zend_get_std_object_handlers(),
  533. sizeof(zend_object_handlers));
  534. zend_internal_iterator_handlers.free_obj = zend_internal_iterator_free;
  535. }
  536. /* }}} */