You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1514 lines
54 KiB

23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
21 years ago
22 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
22 years ago
22 years ago
21 years ago
20 years ago
20 years ago
20 years ago
21 years ago
21 years ago
21 years ago
21 years ago
22 years ago
22 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
23 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
23 years ago
23 years ago
22 years ago
23 years ago
21 years ago
21 years ago
23 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2006 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Marcus Boerger <helly@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #ifdef HAVE_CONFIG_H
  20. # include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #include "ext/standard/info.h"
  25. #include "zend_interfaces.h"
  26. #include "zend_exceptions.h"
  27. #include "php_spl.h"
  28. #include "spl_functions.h"
  29. #include "spl_engine.h"
  30. #include "spl_iterators.h"
  31. #include "spl_array.h"
  32. #include "spl_exceptions.h"
  33. zend_object_handlers spl_handler_ArrayObject;
  34. PHPAPI zend_class_entry *spl_ce_ArrayObject;
  35. zend_object_handlers spl_handler_ArrayIterator;
  36. PHPAPI zend_class_entry *spl_ce_ArrayIterator;
  37. PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
  38. PHPAPI zend_class_entry *spl_ce_Countable;
  39. #define SPL_ARRAY_STD_PROP_LIST 0x00000001
  40. #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
  41. #define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
  42. #define SPL_ARRAY_OVERLOADED_VALID 0x00020000
  43. #define SPL_ARRAY_OVERLOADED_KEY 0x00040000
  44. #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
  45. #define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
  46. #define SPL_ARRAY_IS_REF 0x01000000
  47. #define SPL_ARRAY_IS_SELF 0x02000000
  48. #define SPL_ARRAY_USE_OTHER 0x04000000
  49. #define SPL_ARRAY_INT_MASK 0xFFFF0000
  50. #define SPL_ARRAY_CLONE_MASK 0x03000007
  51. typedef struct _spl_array_object {
  52. zend_object std;
  53. zval *array;
  54. zval *retval;
  55. HashPosition pos;
  56. int ar_flags;
  57. int is_self;
  58. zend_function * fptr_offset_get;
  59. zend_function * fptr_offset_set;
  60. zend_function * fptr_offset_has;
  61. zend_function * fptr_offset_del;
  62. zend_class_entry* ce_get_iterator;
  63. } spl_array_object;
  64. static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) {
  65. if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
  66. return intern->std.properties;
  67. } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0)) {
  68. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
  69. return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
  70. } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
  71. return intern->std.properties;
  72. } else {
  73. return HASH_OF(intern->array);
  74. }
  75. }
  76. SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
  77. {
  78. HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  79. Bucket *p;
  80. /* IS_CONSISTENT(ht);*/
  81. /* HASH_PROTECT_RECURSION(ht);*/
  82. p = ht->pListHead;
  83. while (p != NULL) {
  84. if (p == intern->pos) {
  85. return SUCCESS;
  86. }
  87. p = p->pListNext;
  88. }
  89. /* HASH_UNPROTECT_RECURSION(ht); */
  90. zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
  91. return FAILURE;
  92. }
  93. /* }}} */
  94. /* {{{ spl_array_object_free_storage */
  95. static void spl_array_object_free_storage(void *object TSRMLS_DC)
  96. {
  97. spl_array_object *intern = (spl_array_object *)object;
  98. zend_object_std_dtor(&intern->std TSRMLS_CC);
  99. zval_ptr_dtor(&intern->array);
  100. zval_ptr_dtor(&intern->retval);
  101. efree(object);
  102. }
  103. /* }}} */
  104. zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
  105. /* {{{ spl_array_object_new */
  106. static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
  107. {
  108. zend_object_value retval;
  109. spl_array_object *intern;
  110. zval *tmp;
  111. zend_class_entry * parent = class_type;
  112. int inherited = 0;
  113. intern = emalloc(sizeof(spl_array_object));
  114. memset(intern, 0, sizeof(spl_array_object));
  115. *obj = intern;
  116. ALLOC_INIT_ZVAL(intern->retval);
  117. zend_object_std_init(&intern->std, class_type TSRMLS_CC);
  118. zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  119. intern->ar_flags = 0;
  120. intern->ce_get_iterator = spl_ce_ArrayIterator;
  121. if (orig) {
  122. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
  123. intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
  124. intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
  125. intern->ce_get_iterator = other->ce_get_iterator;
  126. if (clone_orig) {
  127. intern->array = other->array;
  128. if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
  129. MAKE_STD_ZVAL(intern->array);
  130. array_init(intern->array);
  131. zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
  132. }
  133. if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
  134. ZVAL_ADDREF(other->array);
  135. }
  136. } else {
  137. intern->array = orig;
  138. ZVAL_ADDREF(intern->array);
  139. intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
  140. }
  141. } else {
  142. MAKE_STD_ZVAL(intern->array);
  143. array_init(intern->array);
  144. intern->ar_flags &= ~SPL_ARRAY_IS_REF;
  145. }
  146. retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
  147. while (parent) {
  148. if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
  149. retval.handlers = &spl_handler_ArrayIterator;
  150. class_type->get_iterator = spl_array_get_iterator;
  151. break;
  152. } else if (parent == spl_ce_ArrayObject) {
  153. retval.handlers = &spl_handler_ArrayObject;
  154. break;
  155. }
  156. parent = parent->parent;
  157. inherited = 1;
  158. }
  159. if (!parent) { /* this must never happen */
  160. php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
  161. }
  162. if (inherited) {
  163. zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
  164. if (intern->fptr_offset_get->common.scope == parent) {
  165. intern->fptr_offset_get = NULL;
  166. }
  167. zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
  168. if (intern->fptr_offset_set->common.scope == parent) {
  169. intern->fptr_offset_set = NULL;
  170. }
  171. zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
  172. if (intern->fptr_offset_has->common.scope == parent) {
  173. intern->fptr_offset_has = NULL;
  174. }
  175. zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
  176. if (intern->fptr_offset_del->common.scope == parent) {
  177. intern->fptr_offset_del = NULL;
  178. }
  179. }
  180. /* Cache iterator functions if ArrayIterator or derived. Check current's */
  181. /* cache since only current is always required */
  182. if (retval.handlers == &spl_handler_ArrayIterator) {
  183. if (!class_type->iterator_funcs.zf_current) {
  184. zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
  185. zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
  186. zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
  187. zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
  188. zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
  189. }
  190. if (inherited) {
  191. if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
  192. if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
  193. if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
  194. if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
  195. if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
  196. }
  197. }
  198. zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
  199. return retval;
  200. }
  201. /* }}} */
  202. /* {{{ spl_array_object_new */
  203. static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
  204. {
  205. spl_array_object *tmp;
  206. return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
  207. }
  208. /* }}} */
  209. /* {{{ spl_array_object_clone */
  210. static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
  211. {
  212. zend_object_value new_obj_val;
  213. zend_object *old_object;
  214. zend_object *new_object;
  215. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  216. spl_array_object *intern;
  217. old_object = zend_objects_get_address(zobject TSRMLS_CC);
  218. new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
  219. new_object = &intern->std;
  220. zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
  221. return new_obj_val;
  222. }
  223. /* }}} */
  224. static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  225. {
  226. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  227. zval **retval;
  228. long index;
  229. /* We cannot get the pointer pointer so we don't allow it here for now
  230. if (check_inherited && intern->fptr_offset_get) {
  231. return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
  232. }*/
  233. if (!offset) {
  234. return &EG(uninitialized_zval_ptr);
  235. }
  236. switch(Z_TYPE_P(offset)) {
  237. case IS_STRING:
  238. if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
  239. zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset));
  240. return &EG(uninitialized_zval_ptr);
  241. } else {
  242. return retval;
  243. }
  244. case IS_DOUBLE:
  245. case IS_RESOURCE:
  246. case IS_BOOL:
  247. case IS_LONG:
  248. if (offset->type == IS_DOUBLE) {
  249. index = (long)Z_DVAL_P(offset);
  250. } else {
  251. index = Z_LVAL_P(offset);
  252. }
  253. if (zend_hash_index_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void **) &retval) == FAILURE) {
  254. zend_error(E_NOTICE, "Undefined offset: %ld", Z_LVAL_P(offset));
  255. return &EG(uninitialized_zval_ptr);
  256. } else {
  257. return retval;
  258. }
  259. break;
  260. default:
  261. zend_error(E_WARNING, "Illegal offset type");
  262. return &EG(uninitialized_zval_ptr);
  263. }
  264. } /* }}} */
  265. static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  266. {
  267. if (check_inherited) {
  268. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  269. if (intern->fptr_offset_get) {
  270. zval *rv;
  271. SEPARATE_ARG_IF_REF(offset);
  272. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
  273. zval_ptr_dtor(&offset);
  274. if (rv) {
  275. zval_ptr_dtor(&intern->retval);
  276. MAKE_STD_ZVAL(intern->retval);
  277. ZVAL_ZVAL(intern->retval, rv, 1, 1);
  278. return intern->retval;
  279. }
  280. return EG(uninitialized_zval_ptr);
  281. }
  282. }
  283. return *spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
  284. } /* }}} */
  285. static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  286. {
  287. return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
  288. } /* }}} */
  289. static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
  290. {
  291. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  292. long index;
  293. if (check_inherited && intern->fptr_offset_set) {
  294. if (!offset) {
  295. ALLOC_INIT_ZVAL(offset);
  296. } else {
  297. SEPARATE_ARG_IF_REF(offset);
  298. }
  299. zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
  300. zval_ptr_dtor(&offset);
  301. return;
  302. }
  303. if (!offset) {
  304. value->refcount++;
  305. zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
  306. return;
  307. }
  308. switch(Z_TYPE_P(offset)) {
  309. case IS_STRING:
  310. if (*Z_STRVAL_P(offset) == '\0') {
  311. zend_throw_exception(spl_ce_InvalidArgumentException, "An offset must not begin with \\0 or be empty", 0 TSRMLS_CC);
  312. return;
  313. }
  314. value->refcount++;
  315. zend_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
  316. return;
  317. case IS_DOUBLE:
  318. case IS_RESOURCE:
  319. case IS_BOOL:
  320. case IS_LONG:
  321. if (offset->type == IS_DOUBLE) {
  322. index = (long)Z_DVAL_P(offset);
  323. } else {
  324. index = Z_LVAL_P(offset);
  325. }
  326. value->refcount++;
  327. zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
  328. return;
  329. case IS_NULL:
  330. value->refcount++;
  331. zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
  332. return;
  333. default:
  334. zend_error(E_WARNING, "Illegal offset type");
  335. return;
  336. }
  337. } /* }}} */
  338. static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
  339. {
  340. spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
  341. } /* }}} */
  342. static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
  343. {
  344. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  345. long index;
  346. if (check_inherited && intern->fptr_offset_del) {
  347. SEPARATE_ARG_IF_REF(offset);
  348. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
  349. zval_ptr_dtor(&offset);
  350. return;
  351. }
  352. switch(Z_TYPE_P(offset)) {
  353. case IS_STRING:
  354. if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
  355. if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
  356. zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
  357. }
  358. } else {
  359. if (zend_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
  360. zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
  361. }
  362. }
  363. break;
  364. case IS_DOUBLE:
  365. case IS_RESOURCE:
  366. case IS_BOOL:
  367. case IS_LONG:
  368. if (offset->type == IS_DOUBLE) {
  369. index = (long)Z_DVAL_P(offset);
  370. } else {
  371. index = Z_LVAL_P(offset);
  372. }
  373. if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
  374. zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
  375. }
  376. break;
  377. default:
  378. zend_error(E_WARNING, "Illegal offset type");
  379. return;
  380. }
  381. spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
  382. } /* }}} */
  383. static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
  384. {
  385. spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
  386. } /* }}} */
  387. static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
  388. {
  389. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  390. long index;
  391. zval *rv;
  392. if (check_inherited && intern->fptr_offset_has) {
  393. SEPARATE_ARG_IF_REF(offset);
  394. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
  395. zval_ptr_dtor(&offset);
  396. if (rv && zend_is_true(rv)) {
  397. zval_ptr_dtor(&rv);
  398. return 1;
  399. }
  400. if (rv) {
  401. zval_ptr_dtor(&rv);
  402. }
  403. return 0;
  404. }
  405. switch(Z_TYPE_P(offset)) {
  406. case IS_STRING:
  407. return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
  408. case IS_DOUBLE:
  409. case IS_RESOURCE:
  410. case IS_BOOL:
  411. case IS_LONG:
  412. if (offset->type == IS_DOUBLE) {
  413. index = (long)Z_DVAL_P(offset);
  414. } else {
  415. index = Z_LVAL_P(offset);
  416. }
  417. return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
  418. default:
  419. zend_error(E_WARNING, "Illegal offset type");
  420. }
  421. return 0;
  422. } /* }}} */
  423. static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
  424. {
  425. return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
  426. } /* }}} */
  427. /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
  428. proto bool ArrayIterator::offsetExists(mixed $index)
  429. Returns whether the requested $index exists. */
  430. SPL_METHOD(Array, offsetExists)
  431. {
  432. zval *index;
  433. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  434. return;
  435. }
  436. RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 1 TSRMLS_CC));
  437. } /* }}} */
  438. /* {{{ proto bool ArrayObject::offsetGet(mixed $index)
  439. proto bool ArrayIterator::offsetGet(mixed $index)
  440. Returns the value at the specified $index. */
  441. SPL_METHOD(Array, offsetGet)
  442. {
  443. zval *index, *value;
  444. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  445. return;
  446. }
  447. value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
  448. RETURN_ZVAL(value, 1, 0);
  449. } /* }}} */
  450. /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
  451. proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
  452. Sets the value at the specified $index to $newval. */
  453. SPL_METHOD(Array, offsetSet)
  454. {
  455. zval *index, *value;
  456. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
  457. return;
  458. }
  459. spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
  460. } /* }}} */
  461. void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
  462. {
  463. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  464. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  465. if (!aht) {
  466. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  467. return;
  468. }
  469. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  470. php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
  471. return;
  472. }
  473. spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
  474. if (!intern->pos) {
  475. intern->pos = aht->pListTail;
  476. }
  477. } /* }}} */
  478. /* {{{ proto void ArrayObject::append(mixed $newval)
  479. proto void ArrayIterator::append(mixed $newval)
  480. Appends the value (cannot be called for objects). */
  481. SPL_METHOD(Array, append)
  482. {
  483. zval *value;
  484. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
  485. return;
  486. }
  487. spl_array_iterator_append(getThis(), value TSRMLS_CC);
  488. } /* }}} */
  489. /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
  490. proto void ArrayIterator::offsetUnset(mixed $index)
  491. Unsets the value at the specified $index. */
  492. SPL_METHOD(Array, offsetUnset)
  493. {
  494. zval *index;
  495. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  496. return;
  497. }
  498. spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
  499. } /* }}} */
  500. /* {{ proto array ArrayObject::getArrayCopy()
  501. proto array ArrayIterator::getArrayCopy()
  502. Return a copy of the contained array */
  503. SPL_METHOD(Array, getArrayCopy)
  504. {
  505. zval *object = getThis(), *tmp;
  506. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  507. array_init(return_value);
  508. zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
  509. } /* }}} */
  510. static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
  511. {
  512. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  513. return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
  514. } /* }}} */
  515. static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
  516. {
  517. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  518. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  519. && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
  520. return spl_array_read_dimension(object, member, type TSRMLS_CC);
  521. }
  522. return std_object_handlers.read_property(object, member, type TSRMLS_CC);
  523. } /* }}} */
  524. static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
  525. {
  526. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  527. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  528. && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
  529. spl_array_write_dimension(object, member, value TSRMLS_CC);
  530. return;
  531. }
  532. std_object_handlers.write_property(object, member, value TSRMLS_CC);
  533. } /* }}} */
  534. static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
  535. {
  536. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  537. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  538. && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
  539. return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC);
  540. }
  541. return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
  542. } /* }}} */
  543. static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
  544. {
  545. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  546. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0) {
  547. if (!std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
  548. return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
  549. }
  550. return 0; /* if prop doesn't exist at all mode 0/1 cannot return 1 */
  551. }
  552. return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
  553. } /* }}} */
  554. static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
  555. static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
  556. {
  557. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  558. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  559. && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
  560. spl_array_unset_dimension(object, member TSRMLS_CC);
  561. spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
  562. return;
  563. }
  564. std_object_handlers.unset_property(object, member TSRMLS_CC);
  565. } /* }}} */
  566. static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ */
  567. {
  568. char *string_key;
  569. uint string_length;
  570. ulong num_key;
  571. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  572. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  573. do {
  574. if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
  575. if (!string_length || string_key[0]) {
  576. return SUCCESS;
  577. }
  578. } else {
  579. return SUCCESS;
  580. }
  581. if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
  582. return FAILURE;
  583. }
  584. zend_hash_move_forward_ex(aht, &intern->pos);
  585. } while (1);
  586. }
  587. return FAILURE;
  588. }
  589. /* }}} */
  590. static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
  591. {
  592. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  593. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  594. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  595. return FAILURE;
  596. } else {
  597. zend_hash_move_forward_ex(aht, &intern->pos);
  598. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  599. return spl_array_skip_protected(intern TSRMLS_CC);
  600. } else {
  601. return zend_hash_has_more_elements_ex(aht, &intern->pos);
  602. }
  603. }
  604. } /* }}} */
  605. /* define an overloaded iterator structure */
  606. typedef struct {
  607. zend_user_iterator intern;
  608. spl_array_object *object;
  609. } spl_array_it;
  610. static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  611. {
  612. spl_array_it *iterator = (spl_array_it *)iter;
  613. zend_user_it_invalidate_current(iter TSRMLS_CC);
  614. zval_ptr_dtor((zval**)&iterator->intern.it.data);
  615. efree(iterator);
  616. }
  617. /* }}} */
  618. static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  619. {
  620. spl_array_it *iterator = (spl_array_it *)iter;
  621. spl_array_object *object = iterator->object;
  622. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  623. if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
  624. return zend_user_it_valid(iter TSRMLS_CC);
  625. } else {
  626. if (!aht) {
  627. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
  628. return FAILURE;
  629. }
  630. if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
  631. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
  632. return FAILURE;
  633. } else {
  634. return zend_hash_has_more_elements_ex(aht, &object->pos);
  635. }
  636. }
  637. }
  638. /* }}} */
  639. static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
  640. {
  641. spl_array_it *iterator = (spl_array_it *)iter;
  642. spl_array_object *object = iterator->object;
  643. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  644. if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
  645. zend_user_it_get_current_data(iter, data TSRMLS_CC);
  646. } else {
  647. if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
  648. *data = NULL;
  649. }
  650. }
  651. }
  652. /* }}} */
  653. static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
  654. {
  655. spl_array_it *iterator = (spl_array_it *)iter;
  656. spl_array_object *object = iterator->object;
  657. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  658. if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
  659. return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
  660. } else {
  661. if (!aht) {
  662. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
  663. return HASH_KEY_NON_EXISTANT;
  664. }
  665. if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
  666. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
  667. return HASH_KEY_NON_EXISTANT;
  668. }
  669. return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
  670. }
  671. }
  672. /* }}} */
  673. static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  674. {
  675. spl_array_it *iterator = (spl_array_it *)iter;
  676. spl_array_object *object = iterator->object;
  677. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  678. if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
  679. zend_user_it_move_forward(iter TSRMLS_CC);
  680. } else {
  681. zend_user_it_invalidate_current(iter TSRMLS_CC);
  682. if (!aht) {
  683. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
  684. return;
  685. }
  686. if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
  687. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
  688. } else {
  689. spl_array_next(object TSRMLS_CC);
  690. }
  691. }
  692. }
  693. /* }}} */
  694. static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
  695. {
  696. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  697. if (!aht) {
  698. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
  699. return;
  700. }
  701. zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
  702. spl_array_skip_protected(intern TSRMLS_CC);
  703. }
  704. /* }}} */
  705. static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  706. {
  707. spl_array_it *iterator = (spl_array_it *)iter;
  708. spl_array_object *object = iterator->object;
  709. if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
  710. zend_user_it_rewind(iter TSRMLS_CC);
  711. } else {
  712. zend_user_it_invalidate_current(iter TSRMLS_CC);
  713. spl_array_rewind(object TSRMLS_CC);
  714. }
  715. }
  716. /* }}} */
  717. /* iterator handler table */
  718. zend_object_iterator_funcs spl_array_it_funcs = {
  719. spl_array_it_dtor,
  720. spl_array_it_valid,
  721. spl_array_it_get_current_data,
  722. spl_array_it_get_current_key,
  723. spl_array_it_move_forward,
  724. spl_array_it_rewind
  725. };
  726. zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
  727. {
  728. spl_array_it *iterator;
  729. spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  730. if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
  731. zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
  732. }
  733. iterator = emalloc(sizeof(spl_array_it));
  734. object->refcount++;
  735. iterator->intern.it.data = (void*)object;
  736. iterator->intern.it.funcs = &spl_array_it_funcs;
  737. iterator->intern.ce = ce;
  738. iterator->intern.value = NULL;
  739. iterator->object = array_object;
  740. return (zend_object_iterator*)iterator;
  741. }
  742. /* }}} */
  743. /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
  744. proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
  745. Cronstructs a new array iterator from a path. */
  746. SPL_METHOD(Array, __construct)
  747. {
  748. zval *object = getThis();
  749. spl_array_object *intern;
  750. zval *array;
  751. long ar_flags = 0;
  752. char *class_name;
  753. int class_name_len;
  754. zend_class_entry ** pce_get_iterator;
  755. if (ZEND_NUM_ARGS() == 0) {
  756. return; /* nothing to do */
  757. }
  758. php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
  759. intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  760. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ls", &array, &ar_flags, &class_name, &class_name_len) == FAILURE) {
  761. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  762. return;
  763. }
  764. if (ZEND_NUM_ARGS() > 2) {
  765. if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) {
  766. zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC);
  767. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  768. return;
  769. }
  770. intern->ce_get_iterator = *pce_get_iterator;
  771. }
  772. ar_flags &= ~SPL_ARRAY_INT_MASK;
  773. if (Z_TYPE_P(array) == IS_OBJECT && (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator)) {
  774. zval_ptr_dtor(&intern->array);
  775. if (ZEND_NUM_ARGS() == 1)
  776. {
  777. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(array TSRMLS_CC);
  778. ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
  779. }
  780. ar_flags |= SPL_ARRAY_USE_OTHER;
  781. intern->array = array;
  782. } else {
  783. if (Z_TYPE_P(array) != IS_OBJECT && Z_TYPE_P(array) != IS_ARRAY) {
  784. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  785. zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
  786. return;
  787. }
  788. zval_ptr_dtor(&intern->array);
  789. intern->array = array;
  790. }
  791. if (object == array) {
  792. intern->ar_flags |= SPL_ARRAY_IS_SELF;
  793. intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
  794. } else {
  795. intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
  796. }
  797. intern->ar_flags |= ar_flags;
  798. ZVAL_ADDREF(intern->array);
  799. if (Z_TYPE_P(array) == IS_OBJECT) {
  800. zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties);
  801. if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
  802. || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
  803. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  804. zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_P(array)->name, intern->std.ce->name);
  805. return;
  806. }
  807. }
  808. spl_array_rewind(intern TSRMLS_CC);
  809. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  810. }
  811. /* }}} */
  812. /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
  813. Set the class used in getIterator. */
  814. SPL_METHOD(Array, setIteratorClass)
  815. {
  816. zval *object = getThis();
  817. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  818. char *class_name;
  819. int class_name_len;
  820. zend_class_entry ** pce_get_iterator;
  821. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) {
  822. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  823. return;
  824. }
  825. if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) {
  826. zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC);
  827. php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
  828. return;
  829. }
  830. intern->ce_get_iterator = *pce_get_iterator;
  831. }
  832. /* }}} */
  833. /* {{{ proto string ArrayObject::getIteratorClass()
  834. Get the class used in getIterator. */
  835. SPL_METHOD(Array, getIteratorClass)
  836. {
  837. zval *object = getThis();
  838. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  839. RETURN_STRING(intern->ce_get_iterator->name, 1);
  840. }
  841. /* }}} */
  842. /* {{{ proto int ArrayObject::getFlags()
  843. Get flags */
  844. SPL_METHOD(Array, getFlags)
  845. {
  846. zval *object = getThis();
  847. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  848. RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
  849. }
  850. /* }}} */
  851. /* {{{ proto void ArrayObject::setFlags(int flags)
  852. Set flags */
  853. SPL_METHOD(Array, setFlags)
  854. {
  855. zval *object = getThis();
  856. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  857. long ar_flags = 0;
  858. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
  859. return;
  860. }
  861. intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
  862. }
  863. /* }}} */
  864. /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
  865. Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
  866. SPL_METHOD(Array, exchangeArray)
  867. {
  868. zval *object = getThis(), *tmp, **array;
  869. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  870. array_init(return_value);
  871. zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
  872. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
  873. WRONG_PARAM_COUNT;
  874. }
  875. if (Z_TYPE_PP(array) == IS_OBJECT && intern == (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC)) {
  876. zval_ptr_dtor(&intern->array);
  877. array = &object;
  878. intern->array = object;
  879. } else if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
  880. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
  881. zval_ptr_dtor(&intern->array);
  882. intern->array = other->array;
  883. } else {
  884. if (Z_TYPE_PP(array) != IS_OBJECT && !HASH_OF(*array)) {
  885. zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
  886. return;
  887. }
  888. zval_ptr_dtor(&intern->array);
  889. intern->array = *array;
  890. }
  891. if (object == *array) {
  892. intern->ar_flags |= SPL_ARRAY_IS_SELF;
  893. } else {
  894. intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
  895. }
  896. ZVAL_ADDREF(intern->array);
  897. spl_array_rewind(intern TSRMLS_CC);
  898. }
  899. /* }}} */
  900. /* {{{ proto ArrayIterator ArrayObject::getIterator()
  901. Create a new iterator from a ArrayObject instance */
  902. SPL_METHOD(Array, getIterator)
  903. {
  904. zval *object = getThis();
  905. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  906. spl_array_object *iterator;
  907. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  908. if (!aht) {
  909. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  910. return;
  911. }
  912. return_value->type = IS_OBJECT;
  913. return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
  914. return_value->refcount = 1;
  915. return_value->is_ref = 1;
  916. }
  917. /* }}} */
  918. /* {{{ proto void ArrayIterator::rewind()
  919. Rewind array back to the start */
  920. SPL_METHOD(Array, rewind)
  921. {
  922. zval *object = getThis();
  923. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  924. spl_array_rewind(intern TSRMLS_CC);
  925. }
  926. /* }}} */
  927. /* {{{ proto void ArrayIterator::seek(int $position)
  928. Seek to position. */
  929. SPL_METHOD(Array, seek)
  930. {
  931. long opos, position;
  932. zval *object = getThis();
  933. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  934. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  935. int result;
  936. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
  937. return;
  938. }
  939. if (!aht) {
  940. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  941. return;
  942. }
  943. opos = position;
  944. if (position >= 0) { /* negative values are not supported */
  945. zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
  946. result = SUCCESS;
  947. while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
  948. if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
  949. return; /* ok */
  950. }
  951. }
  952. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
  953. } /* }}} */
  954. int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
  955. {
  956. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  957. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  958. HashPosition pos;
  959. if (!aht) {
  960. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  961. *count = 0;
  962. return FAILURE;
  963. }
  964. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  965. /* We need to store the 'pos' since we'll modify it in the functions
  966. * we're going to call and which do not support 'pos' as parameter. */
  967. pos = intern->pos;
  968. *count = 0;
  969. zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
  970. while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
  971. (*count)++;
  972. }
  973. intern->pos = pos;
  974. return SUCCESS;
  975. } else {
  976. *count = zend_hash_num_elements(aht);
  977. return SUCCESS;
  978. }
  979. } /* }}} */
  980. /* {{{ proto int ArrayObject::count()
  981. proto int ArrayIterator::count()
  982. Return the number of elements in the Iterator. */
  983. SPL_METHOD(Array, count)
  984. {
  985. long count;
  986. spl_array_object_count_elements(getThis(), &count TSRMLS_CC);
  987. RETURN_LONG(count);
  988. } /* }}} */
  989. static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
  990. {
  991. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  992. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  993. zval tmp, *arg;
  994. INIT_PZVAL(&tmp);
  995. Z_TYPE(tmp) = IS_ARRAY;
  996. Z_ARRVAL(tmp) = aht;
  997. if (use_arg) {
  998. if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
  999. zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
  1000. return;
  1001. }
  1002. zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 2, &tmp, arg TSRMLS_CC);
  1003. } else {
  1004. zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 1, &tmp, NULL TSRMLS_CC);
  1005. }
  1006. }
  1007. #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
  1008. SPL_METHOD(cname, fname) \
  1009. { \
  1010. spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
  1011. }
  1012. /* {{{ proto int ArrayObject::asort()
  1013. proto int ArrayIterator::asort()
  1014. Sort the entries by values. */
  1015. SPL_ARRAY_METHOD(Array, asort, 0)
  1016. /* {{{ proto int ArrayObject::ksort()
  1017. proto int ArrayIterator::ksort()
  1018. Sort the entries by key. */
  1019. SPL_ARRAY_METHOD(Array, ksort, 0)
  1020. /* {{{ proto int ArrayObject::uasort(callback cmp_function)
  1021. proto int ArrayIterator::uasort(callback cmp_function)
  1022. Sort the entries by values user defined function. */
  1023. SPL_ARRAY_METHOD(Array, uasort, 1)
  1024. /* {{{ proto int ArrayObject::uksort(callback cmp_function)
  1025. proto int ArrayIterator::uksort(callback cmp_function)
  1026. Sort the entries by key using user defined function. */
  1027. SPL_ARRAY_METHOD(Array, uksort, 1)
  1028. /* {{{ proto int ArrayObject::natsort()
  1029. proto int ArrayIterator::natsort()
  1030. Sort the entries by values using "natural order" algorithm. */
  1031. SPL_ARRAY_METHOD(Array, natsort, 0)
  1032. /* {{{ proto int ArrayObject::natcasesort()
  1033. proto int ArrayIterator::natcasesort()
  1034. Sort the entries by key using case insensitive "natural order" algorithm. */
  1035. SPL_ARRAY_METHOD(Array, natcasesort, 0)
  1036. /* {{{ proto mixed|NULL ArrayIterator::current()
  1037. Return current array entry */
  1038. SPL_METHOD(Array, current)
  1039. {
  1040. zval *object = getThis();
  1041. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1042. zval **entry;
  1043. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1044. if (!aht) {
  1045. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1046. return;
  1047. }
  1048. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  1049. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  1050. return;
  1051. }
  1052. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1053. return;
  1054. }
  1055. RETVAL_ZVAL(*entry, 1, 0);
  1056. }
  1057. /* }}} */
  1058. /* {{{ proto mixed|NULL ArrayIterator::key()
  1059. Return current array key */
  1060. SPL_METHOD(Array, key)
  1061. {
  1062. spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
  1063. }
  1064. void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
  1065. {
  1066. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1067. char *string_key;
  1068. uint string_length;
  1069. ulong num_key;
  1070. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1071. if (!aht) {
  1072. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1073. return;
  1074. }
  1075. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  1076. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  1077. return;
  1078. }
  1079. switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
  1080. case HASH_KEY_IS_STRING:
  1081. RETVAL_STRINGL(string_key, string_length - 1, 0);
  1082. break;
  1083. case HASH_KEY_IS_LONG:
  1084. RETVAL_LONG(num_key);
  1085. break;
  1086. case HASH_KEY_NON_EXISTANT:
  1087. return;
  1088. }
  1089. }
  1090. /* }}} */
  1091. /* {{{ proto void ArrayIterator::next()
  1092. Move to next entry */
  1093. SPL_METHOD(Array, next)
  1094. {
  1095. zval *object = getThis();
  1096. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1097. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1098. if (!aht) {
  1099. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1100. return;
  1101. }
  1102. spl_array_next(intern TSRMLS_CC);
  1103. }
  1104. /* }}} */
  1105. /* {{{ proto bool ArrayIterator::valid()
  1106. Check whether array contains more entries */
  1107. SPL_METHOD(Array, valid)
  1108. {
  1109. zval *object = getThis();
  1110. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1111. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1112. if (!aht) {
  1113. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1114. return;
  1115. }
  1116. if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  1117. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  1118. RETURN_FALSE;
  1119. } else {
  1120. RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
  1121. }
  1122. }
  1123. /* }}} */
  1124. /* {{{ proto bool RecursiveArrayIterator::hasChildren()
  1125. Check whether current element has children (e.g. is an array) */
  1126. SPL_METHOD(Array, hasChildren)
  1127. {
  1128. zval *object = getThis(), **entry;
  1129. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1130. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1131. if (!aht) {
  1132. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1133. RETURN_FALSE;
  1134. }
  1135. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  1136. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  1137. RETURN_FALSE;
  1138. }
  1139. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1140. RETURN_FALSE;
  1141. }
  1142. RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT);
  1143. }
  1144. /* }}} */
  1145. /* {{{ proto object RecursiveArrayIterator::getChildren()
  1146. Create a sub iterator for the current element (same class as $this) */
  1147. SPL_METHOD(Array, getChildren)
  1148. {
  1149. zval *object = getThis(), **entry;
  1150. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1151. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1152. if (!aht) {
  1153. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1154. return;
  1155. }
  1156. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
  1157. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  1158. return;
  1159. }
  1160. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1161. return;
  1162. }
  1163. if (Z_TYPE_PP(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
  1164. RETURN_ZVAL(*entry, 0, 0);
  1165. }
  1166. spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, *entry TSRMLS_CC);
  1167. }
  1168. /* }}} */
  1169. static
  1170. ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
  1171. ZEND_ARG_INFO(0, array)
  1172. ZEND_END_ARG_INFO()
  1173. static
  1174. ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
  1175. ZEND_ARG_INFO(0, index)
  1176. ZEND_END_ARG_INFO()
  1177. static
  1178. ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
  1179. ZEND_ARG_INFO(0, index)
  1180. ZEND_ARG_INFO(0, newval)
  1181. ZEND_END_ARG_INFO()
  1182. static
  1183. ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
  1184. ZEND_ARG_INFO(0, value)
  1185. ZEND_END_ARG_INFO()
  1186. static
  1187. ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
  1188. ZEND_ARG_INFO(0, position)
  1189. ZEND_END_ARG_INFO()
  1190. static
  1191. ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
  1192. ZEND_ARG_INFO(0, array)
  1193. ZEND_END_ARG_INFO()
  1194. static
  1195. ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
  1196. ZEND_ARG_INFO(0, flags)
  1197. ZEND_END_ARG_INFO()
  1198. static
  1199. ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
  1200. ZEND_ARG_INFO(0, iteratorClass)
  1201. ZEND_END_ARG_INFO()
  1202. static
  1203. ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
  1204. ZEND_ARG_INFO(0, cmp_function )
  1205. ZEND_END_ARG_INFO();
  1206. static zend_function_entry spl_funcs_ArrayObject[] = {
  1207. SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
  1208. SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1209. SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1210. SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
  1211. SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1212. SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
  1213. SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
  1214. SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
  1215. SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
  1216. SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
  1217. SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
  1218. SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
  1219. SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1220. SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1221. SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
  1222. SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
  1223. /* ArrayObject specific */
  1224. SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC)
  1225. SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
  1226. SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
  1227. SPL_ME(Array, getIteratorClass, NULL, ZEND_ACC_PUBLIC)
  1228. {NULL, NULL, NULL}
  1229. };
  1230. static zend_function_entry spl_funcs_ArrayIterator[] = {
  1231. SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
  1232. SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1233. SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1234. SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
  1235. SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1236. SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
  1237. SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
  1238. SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
  1239. SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
  1240. SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
  1241. SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
  1242. SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
  1243. SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1244. SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1245. SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
  1246. SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
  1247. /* ArrayIterator specific */
  1248. SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC)
  1249. SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC)
  1250. SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC)
  1251. SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC)
  1252. SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC)
  1253. SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
  1254. {NULL, NULL, NULL}
  1255. };
  1256. static zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
  1257. SPL_ME(Array, hasChildren, NULL, ZEND_ACC_PUBLIC)
  1258. SPL_ME(Array, getChildren, NULL, ZEND_ACC_PUBLIC)
  1259. {NULL, NULL, NULL}
  1260. };
  1261. static zend_function_entry spl_funcs_Countable[] = {
  1262. SPL_ABSTRACT_ME(Countable, count, NULL)
  1263. {NULL, NULL, NULL}
  1264. };
  1265. /* {{{ PHP_MINIT_FUNCTION(spl_array) */
  1266. PHP_MINIT_FUNCTION(spl_array)
  1267. {
  1268. REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
  1269. REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
  1270. REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
  1271. memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
  1272. spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
  1273. spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
  1274. spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
  1275. spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
  1276. spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
  1277. spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
  1278. spl_handler_ArrayObject.get_properties = spl_array_get_properties;
  1279. spl_handler_ArrayObject.read_property = spl_array_read_property;
  1280. spl_handler_ArrayObject.write_property = spl_array_write_property;
  1281. spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
  1282. spl_handler_ArrayObject.has_property = spl_array_has_property;
  1283. spl_handler_ArrayObject.unset_property = spl_array_unset_property;
  1284. REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
  1285. REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
  1286. REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
  1287. REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
  1288. memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
  1289. spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
  1290. REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
  1291. REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
  1292. spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
  1293. REGISTER_SPL_INTERFACE(Countable);
  1294. REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
  1295. REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
  1296. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1297. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1298. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1299. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1300. return SUCCESS;
  1301. }
  1302. /* }}} */
  1303. /*
  1304. * Local variables:
  1305. * tab-width: 4
  1306. * c-basic-offset: 4
  1307. * End:
  1308. * vim600: fdm=marker
  1309. * vim: noet sw=4 ts=4
  1310. */