zend_interfaces.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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. *table = &iter->it.data;
  165. *n = 1;
  166. return NULL;
  167. }
  168. static const zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = {
  169. zend_user_it_dtor,
  170. zend_user_it_valid,
  171. zend_user_it_get_current_data,
  172. zend_user_it_get_current_key,
  173. zend_user_it_move_forward,
  174. zend_user_it_rewind,
  175. zend_user_it_invalidate_current,
  176. zend_user_it_get_gc,
  177. };
  178. /* {{{ zend_user_it_get_iterator */
  179. /* by_ref is int due to Iterator API */
  180. static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
  181. {
  182. zend_user_iterator *iterator;
  183. if (by_ref) {
  184. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  185. return NULL;
  186. }
  187. iterator = emalloc(sizeof(zend_user_iterator));
  188. zend_iterator_init((zend_object_iterator*)iterator);
  189. ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
  190. iterator->it.funcs = &zend_interface_iterator_funcs_iterator;
  191. iterator->ce = Z_OBJCE_P(object);
  192. ZVAL_UNDEF(&iterator->value);
  193. return (zend_object_iterator*)iterator;
  194. }
  195. /* }}} */
  196. /* {{{ zend_user_it_get_new_iterator */
  197. /* by_ref is int due to Iterator API */
  198. ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref)
  199. {
  200. zval iterator;
  201. zend_object_iterator *new_iterator;
  202. zend_class_entry *ce_it;
  203. zend_user_it_new_iterator(ce, object, &iterator);
  204. ce_it = (Z_TYPE(iterator) == IS_OBJECT) ? Z_OBJCE(iterator) : NULL;
  205. if (!ce_it || !ce_it->get_iterator || (ce_it->get_iterator == zend_user_it_get_new_iterator && Z_OBJ(iterator) == Z_OBJ_P(object))) {
  206. if (!EG(exception)) {
  207. 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));
  208. }
  209. zval_ptr_dtor(&iterator);
  210. return NULL;
  211. }
  212. new_iterator = ce_it->get_iterator(ce_it, &iterator, by_ref);
  213. zval_ptr_dtor(&iterator);
  214. return new_iterator;
  215. }
  216. /* }}} */
  217. /* {{{ zend_implement_traversable */
  218. static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type)
  219. {
  220. /* Abstract class can implement Traversable only, in which case the extending class must
  221. * implement Iterator or IteratorAggregate. */
  222. if (class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
  223. return SUCCESS;
  224. }
  225. /* Check that class_type implements at least one of 'IteratorAggregate' or 'Iterator' */
  226. if (class_type->num_interfaces) {
  227. ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
  228. for (uint32_t i = 0; i < class_type->num_interfaces; i++) {
  229. if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) {
  230. return SUCCESS;
  231. }
  232. }
  233. }
  234. zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s",
  235. ZSTR_VAL(class_type->name),
  236. ZSTR_VAL(zend_ce_traversable->name),
  237. ZSTR_VAL(zend_ce_iterator->name),
  238. ZSTR_VAL(zend_ce_aggregate->name));
  239. return FAILURE;
  240. }
  241. /* }}} */
  242. /* {{{ zend_implement_aggregate */
  243. static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type)
  244. {
  245. if (zend_class_implements_interface(class_type, zend_ce_iterator)) {
  246. zend_error_noreturn(E_ERROR,
  247. "Class %s cannot implement both Iterator and IteratorAggregate at the same time",
  248. ZSTR_VAL(class_type->name));
  249. }
  250. zend_function *zf = zend_hash_str_find_ptr(
  251. &class_type->function_table, "getiterator", sizeof("getiterator") - 1);
  252. if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_new_iterator) {
  253. /* get_iterator was explicitly assigned for an internal class. */
  254. if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) {
  255. ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS);
  256. return SUCCESS;
  257. }
  258. /* The getIterator() method has not been overwritten, use inherited get_iterator(). */
  259. if (zf->common.scope != class_type) {
  260. return SUCCESS;
  261. }
  262. /* getIterator() has been overwritten, switch to zend_user_it_get_new_iterator. */
  263. }
  264. ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?");
  265. zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS
  266. ? pemalloc(sizeof(zend_class_iterator_funcs), 1)
  267. : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
  268. class_type->get_iterator = zend_user_it_get_new_iterator;
  269. class_type->iterator_funcs_ptr = funcs_ptr;
  270. memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
  271. funcs_ptr->zf_new_iterator = zf;
  272. return SUCCESS;
  273. }
  274. /* }}} */
  275. /* {{{ zend_implement_iterator */
  276. static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type)
  277. {
  278. if (zend_class_implements_interface(class_type, zend_ce_aggregate)) {
  279. zend_error_noreturn(E_ERROR,
  280. "Class %s cannot implement both Iterator and IteratorAggregate at the same time",
  281. ZSTR_VAL(class_type->name));
  282. }
  283. if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) {
  284. if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) {
  285. /* get_iterator was explicitly assigned for an internal class. */
  286. ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS);
  287. return SUCCESS;
  288. }
  289. /* Otherwise get_iterator was inherited from the parent by default. */
  290. }
  291. if (class_type->parent && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) {
  292. /* Keep the inherited get_iterator handler. */
  293. class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR;
  294. } else {
  295. class_type->get_iterator = zend_user_it_get_iterator;
  296. }
  297. ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?");
  298. zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS
  299. ? pemalloc(sizeof(zend_class_iterator_funcs), 1)
  300. : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs));
  301. memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
  302. class_type->iterator_funcs_ptr = funcs_ptr;
  303. return SUCCESS;
  304. }
  305. /* }}} */
  306. /* {{{ zend_user_serialize */
  307. ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
  308. {
  309. zend_class_entry * ce = Z_OBJCE_P(object);
  310. zval retval;
  311. zend_result result;
  312. zend_call_method_with_0_params(
  313. Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "serialize", &retval);
  314. if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) {
  315. result = FAILURE;
  316. } else {
  317. switch(Z_TYPE(retval)) {
  318. case IS_NULL:
  319. /* we could also make this '*buf_len = 0' but this allows to skip variables */
  320. zval_ptr_dtor(&retval);
  321. return FAILURE;
  322. case IS_STRING:
  323. *buffer = (unsigned char*)estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
  324. *buf_len = Z_STRLEN(retval);
  325. result = SUCCESS;
  326. break;
  327. default: /* failure */
  328. result = FAILURE;
  329. break;
  330. }
  331. zval_ptr_dtor(&retval);
  332. }
  333. if (result == FAILURE && !EG(exception)) {
  334. zend_throw_exception_ex(NULL, 0, "%s::serialize() must return a string or NULL", ZSTR_VAL(ce->name));
  335. }
  336. return result;
  337. }
  338. /* }}} */
  339. /* {{{ zend_user_unserialize */
  340. ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
  341. {
  342. zval zdata;
  343. if (UNEXPECTED(object_init_ex(object, ce) != SUCCESS)) {
  344. return FAILURE;
  345. }
  346. ZVAL_STRINGL(&zdata, (char*)buf, buf_len);
  347. zend_call_method_with_1_params(
  348. Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "unserialize", NULL, &zdata);
  349. zval_ptr_dtor(&zdata);
  350. if (EG(exception)) {
  351. return FAILURE;
  352. } else {
  353. return SUCCESS;
  354. }
  355. }
  356. /* }}} */
  357. /* {{{ zend_implement_serializable */
  358. static int zend_implement_serializable(zend_class_entry *interface, zend_class_entry *class_type)
  359. {
  360. if (class_type->parent
  361. && (class_type->parent->serialize || class_type->parent->unserialize)
  362. && !zend_class_implements_interface(class_type->parent, zend_ce_serializable)) {
  363. return FAILURE;
  364. }
  365. if (!class_type->serialize) {
  366. class_type->serialize = zend_user_serialize;
  367. }
  368. if (!class_type->unserialize) {
  369. class_type->unserialize = zend_user_unserialize;
  370. }
  371. if (!(class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)
  372. && (!class_type->__serialize || !class_type->__unserialize)) {
  373. 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));
  374. }
  375. return SUCCESS;
  376. }
  377. /* }}}*/
  378. typedef struct {
  379. zend_object std;
  380. zend_object_iterator *iter;
  381. bool rewind_called;
  382. } zend_internal_iterator;
  383. static zend_object *zend_internal_iterator_create(zend_class_entry *ce) {
  384. zend_internal_iterator *intern = emalloc(sizeof(zend_internal_iterator));
  385. zend_object_std_init(&intern->std, ce);
  386. intern->std.handlers = &zend_internal_iterator_handlers;
  387. intern->iter = NULL;
  388. intern->rewind_called = 0;
  389. return &intern->std;
  390. }
  391. ZEND_API zend_result zend_create_internal_iterator_zval(zval *return_value, zval *obj) {
  392. zend_class_entry *scope = EG(current_execute_data)->func->common.scope;
  393. ZEND_ASSERT(scope->get_iterator != zend_user_it_get_new_iterator);
  394. zend_object_iterator *iter = scope->get_iterator(Z_OBJCE_P(obj), obj, /* by_ref */ 0);
  395. if (!iter) {
  396. return FAILURE;
  397. }
  398. zend_internal_iterator *intern =
  399. (zend_internal_iterator *) zend_internal_iterator_create(zend_ce_internal_iterator);
  400. intern->iter = iter;
  401. intern->iter->index = 0;
  402. ZVAL_OBJ(return_value, &intern->std);
  403. return SUCCESS;
  404. }
  405. static void zend_internal_iterator_free(zend_object *obj) {
  406. zend_internal_iterator *intern = (zend_internal_iterator *) obj;
  407. if (intern->iter) {
  408. zend_iterator_dtor(intern->iter);
  409. }
  410. zend_object_std_dtor(&intern->std);
  411. }
  412. static zend_internal_iterator *zend_internal_iterator_fetch(zval *This) {
  413. zend_internal_iterator *intern = (zend_internal_iterator *) Z_OBJ_P(This);
  414. if (!intern->iter) {
  415. zend_throw_error(NULL, "The InternalIterator object has not been properly initialized");
  416. return NULL;
  417. }
  418. return intern;
  419. }
  420. /* Many iterators will not behave correctly if rewind() is not called, make sure it happens. */
  421. static zend_result zend_internal_iterator_ensure_rewound(zend_internal_iterator *intern) {
  422. if (!intern->rewind_called) {
  423. zend_object_iterator *iter = intern->iter;
  424. intern->rewind_called = 1;
  425. if (iter->funcs->rewind) {
  426. iter->funcs->rewind(iter);
  427. if (UNEXPECTED(EG(exception))) {
  428. return FAILURE;
  429. }
  430. }
  431. }
  432. return SUCCESS;
  433. }
  434. ZEND_METHOD(InternalIterator, __construct) {
  435. zend_throw_error(NULL, "Cannot manually construct InternalIterator");
  436. }
  437. ZEND_METHOD(InternalIterator, current) {
  438. ZEND_PARSE_PARAMETERS_NONE();
  439. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  440. if (!intern) {
  441. RETURN_THROWS();
  442. }
  443. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  444. RETURN_THROWS();
  445. }
  446. zval *data = intern->iter->funcs->get_current_data(intern->iter);
  447. if (data) {
  448. RETURN_COPY_DEREF(data);
  449. }
  450. }
  451. ZEND_METHOD(InternalIterator, key) {
  452. ZEND_PARSE_PARAMETERS_NONE();
  453. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  454. if (!intern) {
  455. RETURN_THROWS();
  456. }
  457. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  458. RETURN_THROWS();
  459. }
  460. if (intern->iter->funcs->get_current_key) {
  461. intern->iter->funcs->get_current_key(intern->iter, return_value);
  462. } else {
  463. RETURN_LONG(intern->iter->index);
  464. }
  465. }
  466. ZEND_METHOD(InternalIterator, next) {
  467. ZEND_PARSE_PARAMETERS_NONE();
  468. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  469. if (!intern) {
  470. RETURN_THROWS();
  471. }
  472. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  473. RETURN_THROWS();
  474. }
  475. /* Advance index first to match foreach behavior. */
  476. intern->iter->index++;
  477. intern->iter->funcs->move_forward(intern->iter);
  478. }
  479. ZEND_METHOD(InternalIterator, valid) {
  480. ZEND_PARSE_PARAMETERS_NONE();
  481. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  482. if (!intern) {
  483. RETURN_THROWS();
  484. }
  485. if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
  486. RETURN_THROWS();
  487. }
  488. RETURN_BOOL(intern->iter->funcs->valid(intern->iter) == SUCCESS);
  489. }
  490. ZEND_METHOD(InternalIterator, rewind) {
  491. ZEND_PARSE_PARAMETERS_NONE();
  492. zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
  493. if (!intern) {
  494. RETURN_THROWS();
  495. }
  496. if (!intern->iter->funcs->rewind) {
  497. /* Allow calling rewind() if no iteration has happened yet,
  498. * even if the iterator does not support rewinding. */
  499. if (intern->iter->index != 0) {
  500. zend_throw_error(NULL, "Iterator does not support rewinding");
  501. RETURN_THROWS();
  502. }
  503. intern->iter->index = 0;
  504. return;
  505. }
  506. intern->iter->funcs->rewind(intern->iter);
  507. intern->iter->index = 0;
  508. }
  509. /* {{{ zend_register_interfaces */
  510. ZEND_API void zend_register_interfaces(void)
  511. {
  512. zend_ce_traversable = register_class_Traversable();
  513. zend_ce_traversable->interface_gets_implemented = zend_implement_traversable;
  514. zend_ce_aggregate = register_class_IteratorAggregate(zend_ce_traversable);
  515. zend_ce_aggregate->interface_gets_implemented = zend_implement_aggregate;
  516. zend_ce_iterator = register_class_Iterator(zend_ce_traversable);
  517. zend_ce_iterator->interface_gets_implemented = zend_implement_iterator;
  518. zend_ce_serializable = register_class_Serializable();
  519. zend_ce_serializable->interface_gets_implemented = zend_implement_serializable;
  520. zend_ce_arrayaccess = register_class_ArrayAccess();
  521. zend_ce_countable = register_class_Countable();
  522. zend_ce_stringable = register_class_Stringable();
  523. zend_ce_internal_iterator = register_class_InternalIterator(zend_ce_iterator);
  524. zend_ce_internal_iterator->create_object = zend_internal_iterator_create;
  525. memcpy(&zend_internal_iterator_handlers, zend_get_std_object_handlers(),
  526. sizeof(zend_object_handlers));
  527. zend_internal_iterator_handlers.free_obj = zend_internal_iterator_free;
  528. }
  529. /* }}} */