spl_array.c 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 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 "ext/standard/php_var.h"
  26. #include "ext/standard/php_smart_str.h"
  27. #include "zend_interfaces.h"
  28. #include "zend_exceptions.h"
  29. #include "php_spl.h"
  30. #include "spl_functions.h"
  31. #include "spl_engine.h"
  32. #include "spl_iterators.h"
  33. #include "spl_array.h"
  34. #include "spl_exceptions.h"
  35. zend_object_handlers spl_handler_ArrayObject;
  36. PHPAPI zend_class_entry *spl_ce_ArrayObject;
  37. zend_object_handlers spl_handler_ArrayIterator;
  38. PHPAPI zend_class_entry *spl_ce_ArrayIterator;
  39. PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
  40. #define SPL_ARRAY_STD_PROP_LIST 0x00000001
  41. #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
  42. #define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004
  43. #define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
  44. #define SPL_ARRAY_OVERLOADED_VALID 0x00020000
  45. #define SPL_ARRAY_OVERLOADED_KEY 0x00040000
  46. #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
  47. #define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
  48. #define SPL_ARRAY_IS_REF 0x01000000
  49. #define SPL_ARRAY_IS_SELF 0x02000000
  50. #define SPL_ARRAY_USE_OTHER 0x04000000
  51. #define SPL_ARRAY_INT_MASK 0xFFFF0000
  52. #define SPL_ARRAY_CLONE_MASK 0x0300FFFF
  53. #define SPL_ARRAY_METHOD_NO_ARG 0
  54. #define SPL_ARRAY_METHOD_USE_ARG 1
  55. #define SPL_ARRAY_METHOD_MAY_USER_ARG 2
  56. typedef struct _spl_array_object {
  57. zend_object std;
  58. zval *array;
  59. zval *retval;
  60. HashPosition pos;
  61. ulong pos_h;
  62. int ar_flags;
  63. int is_self;
  64. zend_function *fptr_offset_get;
  65. zend_function *fptr_offset_set;
  66. zend_function *fptr_offset_has;
  67. zend_function *fptr_offset_del;
  68. zend_function *fptr_count;
  69. zend_class_entry* ce_get_iterator;
  70. HashTable *debug_info;
  71. unsigned char nApplyCount;
  72. } spl_array_object;
  73. static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
  74. if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
  75. if (!intern->std.properties) {
  76. rebuild_object_properties(&intern->std);
  77. }
  78. return intern->std.properties;
  79. } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
  80. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
  81. return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
  82. } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
  83. if (!intern->std.properties) {
  84. rebuild_object_properties(&intern->std);
  85. }
  86. return intern->std.properties;
  87. } else {
  88. return HASH_OF(intern->array);
  89. }
  90. } /* }}} */
  91. static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
  92. static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
  93. {
  94. Bucket *pos = intern->pos;
  95. if (pos != NULL) {
  96. intern->pos_h = pos->h;
  97. }
  98. } /* }}} */
  99. static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
  100. {
  101. intern->pos = pos;
  102. spl_array_update_pos(intern);
  103. } /* }}} */
  104. SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
  105. {
  106. Bucket *p;
  107. /* IS_CONSISTENT(ht);*/
  108. /* HASH_PROTECT_RECURSION(ht);*/
  109. p = ht->arBuckets[intern->pos_h & ht->nTableMask];
  110. while (p != NULL) {
  111. if (p == intern->pos) {
  112. return SUCCESS;
  113. }
  114. p = p->pNext;
  115. }
  116. /* HASH_UNPROTECT_RECURSION(ht); */
  117. spl_array_rewind(intern TSRMLS_CC);
  118. return FAILURE;
  119. } /* }}} */
  120. SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
  121. {
  122. HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  123. return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
  124. }
  125. /* }}} */
  126. /* {{{ spl_array_object_free_storage */
  127. static void spl_array_object_free_storage(void *object TSRMLS_DC)
  128. {
  129. spl_array_object *intern = (spl_array_object *)object;
  130. zend_object_std_dtor(&intern->std TSRMLS_CC);
  131. zval_ptr_dtor(&intern->array);
  132. zval_ptr_dtor(&intern->retval);
  133. if (intern->debug_info != NULL) {
  134. zend_hash_destroy(intern->debug_info);
  135. efree(intern->debug_info);
  136. }
  137. efree(object);
  138. }
  139. /* }}} */
  140. zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
  141. /* {{{ spl_array_object_new_ex */
  142. 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)
  143. {
  144. zend_object_value retval = {0};
  145. spl_array_object *intern;
  146. zval *tmp;
  147. zend_class_entry * parent = class_type;
  148. int inherited = 0;
  149. intern = emalloc(sizeof(spl_array_object));
  150. memset(intern, 0, sizeof(spl_array_object));
  151. *obj = intern;
  152. ALLOC_INIT_ZVAL(intern->retval);
  153. zend_object_std_init(&intern->std, class_type TSRMLS_CC);
  154. object_properties_init(&intern->std, class_type);
  155. intern->ar_flags = 0;
  156. intern->debug_info = NULL;
  157. intern->ce_get_iterator = spl_ce_ArrayIterator;
  158. if (orig) {
  159. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
  160. intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
  161. intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
  162. intern->ce_get_iterator = other->ce_get_iterator;
  163. if (clone_orig) {
  164. intern->array = other->array;
  165. if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
  166. MAKE_STD_ZVAL(intern->array);
  167. array_init(intern->array);
  168. zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
  169. }
  170. if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
  171. Z_ADDREF_P(other->array);
  172. }
  173. } else {
  174. intern->array = orig;
  175. Z_ADDREF_P(intern->array);
  176. intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
  177. }
  178. } else {
  179. MAKE_STD_ZVAL(intern->array);
  180. array_init(intern->array);
  181. intern->ar_flags &= ~SPL_ARRAY_IS_REF;
  182. }
  183. 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);
  184. while (parent) {
  185. if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
  186. retval.handlers = &spl_handler_ArrayIterator;
  187. class_type->get_iterator = spl_array_get_iterator;
  188. break;
  189. } else if (parent == spl_ce_ArrayObject) {
  190. retval.handlers = &spl_handler_ArrayObject;
  191. break;
  192. }
  193. parent = parent->parent;
  194. inherited = 1;
  195. }
  196. if (!parent) { /* this must never happen */
  197. php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
  198. }
  199. if (inherited) {
  200. zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
  201. if (intern->fptr_offset_get->common.scope == parent) {
  202. intern->fptr_offset_get = NULL;
  203. }
  204. zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
  205. if (intern->fptr_offset_set->common.scope == parent) {
  206. intern->fptr_offset_set = NULL;
  207. }
  208. zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
  209. if (intern->fptr_offset_has->common.scope == parent) {
  210. intern->fptr_offset_has = NULL;
  211. }
  212. zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
  213. if (intern->fptr_offset_del->common.scope == parent) {
  214. intern->fptr_offset_del = NULL;
  215. }
  216. zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
  217. if (intern->fptr_count->common.scope == parent) {
  218. intern->fptr_count = NULL;
  219. }
  220. }
  221. /* Cache iterator functions if ArrayIterator or derived. Check current's */
  222. /* cache since only current is always required */
  223. if (retval.handlers == &spl_handler_ArrayIterator) {
  224. if (!class_type->iterator_funcs.zf_current) {
  225. zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
  226. zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
  227. zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
  228. zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
  229. zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
  230. }
  231. if (inherited) {
  232. if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
  233. if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
  234. if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
  235. if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
  236. if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
  237. }
  238. }
  239. spl_array_rewind(intern TSRMLS_CC);
  240. return retval;
  241. }
  242. /* }}} */
  243. /* {{{ spl_array_object_new */
  244. static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
  245. {
  246. spl_array_object *tmp;
  247. return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
  248. }
  249. /* }}} */
  250. /* {{{ spl_array_object_clone */
  251. static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
  252. {
  253. zend_object_value new_obj_val;
  254. zend_object *old_object;
  255. zend_object *new_object;
  256. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  257. spl_array_object *intern;
  258. old_object = zend_objects_get_address(zobject TSRMLS_CC);
  259. new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
  260. new_object = &intern->std;
  261. zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
  262. return new_obj_val;
  263. }
  264. /* }}} */
  265. static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  266. {
  267. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  268. zval **retval;
  269. char *key;
  270. uint len;
  271. long index;
  272. HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  273. if (!offset || !ht) {
  274. return &EG(uninitialized_zval_ptr);
  275. }
  276. if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
  277. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  278. return &EG(error_zval_ptr);;
  279. }
  280. switch (Z_TYPE_P(offset)) {
  281. case IS_STRING:
  282. key = Z_STRVAL_P(offset);
  283. len = Z_STRLEN_P(offset) + 1;
  284. string_offest:
  285. if (zend_symtable_find(ht, key, len, (void **) &retval) == FAILURE) {
  286. switch (type) {
  287. case BP_VAR_R:
  288. zend_error(E_NOTICE, "Undefined index: %s", key);
  289. case BP_VAR_UNSET:
  290. case BP_VAR_IS:
  291. retval = &EG(uninitialized_zval_ptr);
  292. break;
  293. case BP_VAR_RW:
  294. zend_error(E_NOTICE,"Undefined index: %s", key);
  295. case BP_VAR_W: {
  296. zval *value;
  297. ALLOC_INIT_ZVAL(value);
  298. zend_symtable_update(ht, key, len, (void**)&value, sizeof(void*), (void **)&retval);
  299. }
  300. }
  301. }
  302. return retval;
  303. case IS_NULL:
  304. key = "";
  305. len = 1;
  306. goto string_offest;
  307. case IS_RESOURCE:
  308. zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(offset), Z_LVAL_P(offset));
  309. case IS_DOUBLE:
  310. case IS_BOOL:
  311. case IS_LONG:
  312. if (offset->type == IS_DOUBLE) {
  313. index = (long)Z_DVAL_P(offset);
  314. } else {
  315. index = Z_LVAL_P(offset);
  316. }
  317. if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
  318. switch (type) {
  319. case BP_VAR_R:
  320. zend_error(E_NOTICE, "Undefined offset: %ld", index);
  321. case BP_VAR_UNSET:
  322. case BP_VAR_IS:
  323. retval = &EG(uninitialized_zval_ptr);
  324. break;
  325. case BP_VAR_RW:
  326. zend_error(E_NOTICE, "Undefined offset: %ld", index);
  327. case BP_VAR_W: {
  328. zval *value;
  329. ALLOC_INIT_ZVAL(value);
  330. zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), (void **)&retval);
  331. }
  332. }
  333. }
  334. return retval;
  335. default:
  336. zend_error(E_WARNING, "Illegal offset type");
  337. return (type == BP_VAR_W || type == BP_VAR_RW) ?
  338. &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
  339. }
  340. } /* }}} */
  341. static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  342. {
  343. zval **ret;
  344. if (check_inherited) {
  345. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  346. if (intern->fptr_offset_get) {
  347. zval *rv;
  348. if (!offset) {
  349. ALLOC_INIT_ZVAL(offset);
  350. } else {
  351. SEPARATE_ARG_IF_REF(offset);
  352. }
  353. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
  354. zval_ptr_dtor(&offset);
  355. if (rv) {
  356. zval_ptr_dtor(&intern->retval);
  357. MAKE_STD_ZVAL(intern->retval);
  358. ZVAL_ZVAL(intern->retval, rv, 1, 1);
  359. return intern->retval;
  360. }
  361. return EG(uninitialized_zval_ptr);
  362. }
  363. }
  364. ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
  365. /* When in a write context,
  366. * ZE has to be fooled into thinking this is in a reference set
  367. * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
  368. if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) && !Z_ISREF_PP(ret) && ret != &EG(uninitialized_zval_ptr)) {
  369. if (Z_REFCOUNT_PP(ret) > 1) {
  370. zval *newval;
  371. /* Separate */
  372. MAKE_STD_ZVAL(newval);
  373. *newval = **ret;
  374. zval_copy_ctor(newval);
  375. Z_SET_REFCOUNT_P(newval, 1);
  376. /* Replace */
  377. Z_DELREF_PP(ret);
  378. *ret = newval;
  379. }
  380. Z_SET_ISREF_PP(ret);
  381. }
  382. return *ret;
  383. } /* }}} */
  384. static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
  385. {
  386. return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
  387. } /* }}} */
  388. static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
  389. {
  390. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  391. long index;
  392. HashTable *ht;
  393. if (check_inherited && intern->fptr_offset_set) {
  394. if (!offset) {
  395. ALLOC_INIT_ZVAL(offset);
  396. } else {
  397. SEPARATE_ARG_IF_REF(offset);
  398. }
  399. zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
  400. zval_ptr_dtor(&offset);
  401. return;
  402. }
  403. if (!offset) {
  404. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  405. if (ht->nApplyCount > 0) {
  406. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  407. return;
  408. }
  409. Z_ADDREF_P(value);
  410. zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
  411. return;
  412. }
  413. switch(Z_TYPE_P(offset)) {
  414. case IS_STRING:
  415. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  416. if (ht->nApplyCount > 0) {
  417. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  418. return;
  419. }
  420. Z_ADDREF_P(value);
  421. zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
  422. return;
  423. case IS_DOUBLE:
  424. case IS_RESOURCE:
  425. case IS_BOOL:
  426. case IS_LONG:
  427. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  428. if (ht->nApplyCount > 0) {
  429. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  430. return;
  431. }
  432. if (offset->type == IS_DOUBLE) {
  433. index = (long)Z_DVAL_P(offset);
  434. } else {
  435. index = Z_LVAL_P(offset);
  436. }
  437. Z_ADDREF_P(value);
  438. zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
  439. return;
  440. case IS_NULL:
  441. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  442. if (ht->nApplyCount > 0) {
  443. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  444. return;
  445. }
  446. Z_ADDREF_P(value);
  447. zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
  448. return;
  449. default:
  450. zend_error(E_WARNING, "Illegal offset type");
  451. return;
  452. }
  453. } /* }}} */
  454. static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
  455. {
  456. spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
  457. } /* }}} */
  458. static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
  459. {
  460. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  461. long index;
  462. HashTable *ht;
  463. if (check_inherited && intern->fptr_offset_del) {
  464. SEPARATE_ARG_IF_REF(offset);
  465. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
  466. zval_ptr_dtor(&offset);
  467. return;
  468. }
  469. switch(Z_TYPE_P(offset)) {
  470. case IS_STRING:
  471. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  472. if (ht->nApplyCount > 0) {
  473. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  474. return;
  475. }
  476. if (ht == &EG(symbol_table)) {
  477. if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
  478. zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
  479. }
  480. } else {
  481. if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
  482. zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
  483. } else {
  484. spl_array_object *obj = intern;
  485. while (1) {
  486. if ((obj->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
  487. break;
  488. } else if (Z_TYPE_P(obj->array) == IS_OBJECT) {
  489. if ((obj->ar_flags & SPL_ARRAY_USE_OTHER) == 0) {
  490. obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
  491. break;
  492. } else {
  493. obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
  494. }
  495. } else {
  496. obj = NULL;
  497. break;
  498. }
  499. }
  500. if (obj) {
  501. zend_property_info *property_info = zend_get_property_info(obj->std.ce, offset, 1 TSRMLS_CC);
  502. if (property_info &&
  503. (property_info->flags & ZEND_ACC_STATIC) == 0 &&
  504. property_info->offset >= 0) {
  505. obj->std.properties_table[property_info->offset] = NULL;
  506. }
  507. }
  508. }
  509. }
  510. break;
  511. case IS_DOUBLE:
  512. case IS_RESOURCE:
  513. case IS_BOOL:
  514. case IS_LONG:
  515. if (offset->type == IS_DOUBLE) {
  516. index = (long)Z_DVAL_P(offset);
  517. } else {
  518. index = Z_LVAL_P(offset);
  519. }
  520. ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  521. if (ht->nApplyCount > 0) {
  522. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  523. return;
  524. }
  525. if (zend_hash_index_del(ht, index) == FAILURE) {
  526. zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
  527. }
  528. break;
  529. default:
  530. zend_error(E_WARNING, "Illegal offset type");
  531. return;
  532. }
  533. spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
  534. } /* }}} */
  535. static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
  536. {
  537. spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
  538. } /* }}} */
  539. static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
  540. {
  541. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  542. long index;
  543. zval *rv, *value = NULL, **tmp;
  544. if (check_inherited && intern->fptr_offset_has) {
  545. zval *offset_tmp = offset;
  546. SEPARATE_ARG_IF_REF(offset_tmp);
  547. zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset_tmp);
  548. zval_ptr_dtor(&offset_tmp);
  549. if (rv && zend_is_true(rv)) {
  550. zval_ptr_dtor(&rv);
  551. if (check_empty != 1) {
  552. return 1;
  553. } else if (intern->fptr_offset_get) {
  554. value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R TSRMLS_CC);
  555. }
  556. } else {
  557. if (rv) {
  558. zval_ptr_dtor(&rv);
  559. }
  560. return 0;
  561. }
  562. }
  563. if (!value) {
  564. HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  565. switch(Z_TYPE_P(offset)) {
  566. case IS_STRING:
  567. if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) {
  568. if (check_empty == 2) {
  569. return 1;
  570. }
  571. } else {
  572. return 0;
  573. }
  574. break;
  575. case IS_DOUBLE:
  576. case IS_RESOURCE:
  577. case IS_BOOL:
  578. case IS_LONG:
  579. if (offset->type == IS_DOUBLE) {
  580. index = (long)Z_DVAL_P(offset);
  581. } else {
  582. index = Z_LVAL_P(offset);
  583. }
  584. if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
  585. if (check_empty == 2) {
  586. return 1;
  587. }
  588. } else {
  589. return 0;
  590. }
  591. break;
  592. default:
  593. zend_error(E_WARNING, "Illegal offset type");
  594. return 0;
  595. }
  596. if (check_empty && check_inherited && intern->fptr_offset_get) {
  597. value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R TSRMLS_CC);
  598. } else {
  599. value = *tmp;
  600. }
  601. }
  602. return check_empty ? zend_is_true(value) : Z_TYPE_P(value) != IS_NULL;
  603. } /* }}} */
  604. static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
  605. {
  606. return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
  607. } /* }}} */
  608. /* {{{ spl_array_object_verify_pos_ex */
  609. static inline int spl_array_object_verify_pos_ex(spl_array_object *object, HashTable *ht, const char *msg_prefix TSRMLS_DC)
  610. {
  611. if (!ht) {
  612. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and is no longer an array", msg_prefix);
  613. return FAILURE;
  614. }
  615. if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, ht TSRMLS_CC) == FAILURE) {
  616. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and internal position is no longer valid", msg_prefix);
  617. return FAILURE;
  618. }
  619. return SUCCESS;
  620. } /* }}} */
  621. /* {{{ spl_array_object_verify_pos */
  622. static inline int spl_array_object_verify_pos(spl_array_object *object, HashTable *ht TSRMLS_DC)
  623. {
  624. return spl_array_object_verify_pos_ex(object, ht, "" TSRMLS_CC);
  625. } /* }}} */
  626. /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
  627. proto bool ArrayIterator::offsetExists(mixed $index)
  628. Returns whether the requested $index exists. */
  629. SPL_METHOD(Array, offsetExists)
  630. {
  631. zval *index;
  632. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  633. return;
  634. }
  635. RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 2 TSRMLS_CC));
  636. } /* }}} */
  637. /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
  638. proto mixed ArrayIterator::offsetGet(mixed $index)
  639. Returns the value at the specified $index. */
  640. SPL_METHOD(Array, offsetGet)
  641. {
  642. zval *index, *value;
  643. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  644. return;
  645. }
  646. value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
  647. RETURN_ZVAL(value, 1, 0);
  648. } /* }}} */
  649. /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
  650. proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
  651. Sets the value at the specified $index to $newval. */
  652. SPL_METHOD(Array, offsetSet)
  653. {
  654. zval *index, *value;
  655. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
  656. return;
  657. }
  658. spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
  659. } /* }}} */
  660. void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
  661. {
  662. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  663. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  664. if (!aht) {
  665. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  666. return;
  667. }
  668. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  669. php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
  670. return;
  671. }
  672. spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
  673. if (!intern->pos) {
  674. spl_array_set_pos(intern, aht->pListTail);
  675. }
  676. } /* }}} */
  677. /* {{{ proto void ArrayObject::append(mixed $newval)
  678. proto void ArrayIterator::append(mixed $newval)
  679. Appends the value (cannot be called for objects). */
  680. SPL_METHOD(Array, append)
  681. {
  682. zval *value;
  683. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
  684. return;
  685. }
  686. spl_array_iterator_append(getThis(), value TSRMLS_CC);
  687. } /* }}} */
  688. /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
  689. proto void ArrayIterator::offsetUnset(mixed $index)
  690. Unsets the value at the specified $index. */
  691. SPL_METHOD(Array, offsetUnset)
  692. {
  693. zval *index;
  694. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
  695. return;
  696. }
  697. spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
  698. } /* }}} */
  699. /* {{{ proto array ArrayObject::getArrayCopy()
  700. proto array ArrayIterator::getArrayCopy()
  701. Return a copy of the contained array */
  702. SPL_METHOD(Array, getArrayCopy)
  703. {
  704. zval *object = getThis(), *tmp;
  705. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  706. array_init(return_value);
  707. 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*));
  708. } /* }}} */
  709. static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
  710. {
  711. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  712. HashTable *result;
  713. if (intern->nApplyCount > 1) {
  714. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
  715. }
  716. intern->nApplyCount++;
  717. result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
  718. intern->nApplyCount--;
  719. return result;
  720. } /* }}} */
  721. static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
  722. {
  723. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
  724. zval *tmp, *storage;
  725. int name_len;
  726. char *zname;
  727. zend_class_entry *base;
  728. *is_temp = 0;
  729. if (!intern->std.properties) {
  730. rebuild_object_properties(&intern->std);
  731. }
  732. if (HASH_OF(intern->array) == intern->std.properties) {
  733. return intern->std.properties;
  734. } else {
  735. if (intern->debug_info == NULL) {
  736. ALLOC_HASHTABLE(intern->debug_info);
  737. ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
  738. }
  739. if (intern->debug_info->nApplyCount == 0) {
  740. zend_hash_clean(intern->debug_info);
  741. zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  742. storage = intern->array;
  743. zval_add_ref(&storage);
  744. base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
  745. zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
  746. zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
  747. efree(zname);
  748. }
  749. return intern->debug_info;
  750. }
  751. }
  752. /* }}} */
  753. static HashTable *spl_array_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
  754. {
  755. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  756. *gc_data = &intern->array;
  757. *gc_data_count = 1;
  758. return zend_std_get_properties(object TSRMLS_CC);
  759. }
  760. /* }}} */
  761. static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
  762. {
  763. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  764. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  765. && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
  766. return spl_array_read_dimension(object, member, type TSRMLS_CC);
  767. }
  768. return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
  769. } /* }}} */
  770. static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
  771. {
  772. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  773. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  774. && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
  775. spl_array_write_dimension(object, member, value TSRMLS_CC);
  776. return;
  777. }
  778. std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
  779. } /* }}} */
  780. static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
  781. {
  782. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  783. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  784. && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
  785. return spl_array_get_dimension_ptr_ptr(1, object, member, type TSRMLS_CC);
  786. }
  787. return std_object_handlers.get_property_ptr_ptr(object, member, type, key TSRMLS_CC);
  788. } /* }}} */
  789. static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
  790. {
  791. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  792. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  793. && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
  794. return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
  795. }
  796. return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC);
  797. } /* }}} */
  798. static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
  799. {
  800. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  801. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  802. && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
  803. spl_array_unset_dimension(object, member TSRMLS_CC);
  804. spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
  805. return;
  806. }
  807. std_object_handlers.unset_property(object, member, key TSRMLS_CC);
  808. } /* }}} */
  809. static int spl_array_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
  810. {
  811. HashTable *ht1,
  812. *ht2;
  813. spl_array_object *intern1,
  814. *intern2;
  815. int result = 0;
  816. zval temp_zv;
  817. intern1 = (spl_array_object*)zend_object_store_get_object(o1 TSRMLS_CC);
  818. intern2 = (spl_array_object*)zend_object_store_get_object(o2 TSRMLS_CC);
  819. ht1 = spl_array_get_hash_table(intern1, 0 TSRMLS_CC);
  820. ht2 = spl_array_get_hash_table(intern2, 0 TSRMLS_CC);
  821. zend_compare_symbol_tables(&temp_zv, ht1, ht2 TSRMLS_CC);
  822. result = (int)Z_LVAL(temp_zv);
  823. /* if we just compared std.properties, don't do it again */
  824. if (result == 0 &&
  825. !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
  826. result = std_object_handlers.compare_objects(o1, o2 TSRMLS_CC);
  827. }
  828. return result;
  829. } /* }}} */
  830. static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
  831. {
  832. char *string_key;
  833. uint string_length;
  834. ulong num_key;
  835. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  836. do {
  837. if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
  838. /* zend_hash_get_current_key_ex() should never set
  839. * string_length to 0 when returning HASH_KEY_IS_STRING, but we
  840. * may as well be defensive and consider that successful.
  841. * Beyond that, we're looking for protected keys (which will
  842. * have a null byte at string_key[0]), but want to avoid
  843. * skipping completely empty keys (which will also have the
  844. * null byte, but a string_length of 1). */
  845. if (!string_length || string_key[0] || string_length == 1) {
  846. return SUCCESS;
  847. }
  848. } else {
  849. return SUCCESS;
  850. }
  851. if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
  852. return FAILURE;
  853. }
  854. zend_hash_move_forward_ex(aht, &intern->pos);
  855. spl_array_update_pos(intern);
  856. } while (1);
  857. }
  858. return FAILURE;
  859. } /* }}} */
  860. static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
  861. {
  862. zend_hash_move_forward_ex(aht, &intern->pos);
  863. spl_array_update_pos(intern);
  864. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  865. return spl_array_skip_protected(intern, aht TSRMLS_CC);
  866. } else {
  867. return zend_hash_has_more_elements_ex(aht, &intern->pos);
  868. }
  869. } /* }}} */
  870. static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
  871. {
  872. if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
  873. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
  874. return FAILURE;
  875. }
  876. return spl_array_next_no_verify(intern, aht TSRMLS_CC);
  877. } /* }}} */
  878. static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
  879. {
  880. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  881. return spl_array_next_ex(intern, aht TSRMLS_CC);
  882. } /* }}} */
  883. /* define an overloaded iterator structure */
  884. typedef struct {
  885. zend_user_iterator intern;
  886. spl_array_object *object;
  887. } spl_array_it;
  888. static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  889. {
  890. spl_array_it *iterator = (spl_array_it *)iter;
  891. zend_user_it_invalidate_current(iter TSRMLS_CC);
  892. zval_ptr_dtor((zval**)&iterator->intern.it.data);
  893. efree(iterator);
  894. }
  895. /* }}} */
  896. static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  897. {
  898. spl_array_it *iterator = (spl_array_it *)iter;
  899. spl_array_object *object = iterator->object;
  900. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  901. if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
  902. return zend_user_it_valid(iter TSRMLS_CC);
  903. } else {
  904. if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::valid(): " TSRMLS_CC) == FAILURE) {
  905. return FAILURE;
  906. }
  907. return zend_hash_has_more_elements_ex(aht, &object->pos);
  908. }
  909. }
  910. /* }}} */
  911. static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
  912. {
  913. spl_array_it *iterator = (spl_array_it *)iter;
  914. spl_array_object *object = iterator->object;
  915. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  916. if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
  917. zend_user_it_get_current_data(iter, data TSRMLS_CC);
  918. } else {
  919. if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
  920. *data = NULL;
  921. }
  922. }
  923. }
  924. /* }}} */
  925. static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) /* {{{ */
  926. {
  927. spl_array_it *iterator = (spl_array_it *)iter;
  928. spl_array_object *object = iterator->object;
  929. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  930. if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
  931. zend_user_it_get_current_key(iter, key TSRMLS_CC);
  932. } else {
  933. if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) {
  934. ZVAL_NULL(key);
  935. } else {
  936. zend_hash_get_current_key_zval_ex(aht, key, &object->pos);
  937. }
  938. }
  939. }
  940. /* }}} */
  941. static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  942. {
  943. spl_array_it *iterator = (spl_array_it *)iter;
  944. spl_array_object *object = iterator->object;
  945. HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
  946. if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
  947. zend_user_it_move_forward(iter TSRMLS_CC);
  948. } else {
  949. zend_user_it_invalidate_current(iter TSRMLS_CC);
  950. if (!aht) {
  951. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
  952. return;
  953. }
  954. if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
  955. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
  956. } else {
  957. spl_array_next_no_verify(object, aht TSRMLS_CC);
  958. }
  959. }
  960. }
  961. /* }}} */
  962. static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
  963. {
  964. zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
  965. spl_array_update_pos(intern);
  966. spl_array_skip_protected(intern, aht TSRMLS_CC);
  967. } /* }}} */
  968. static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
  969. {
  970. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  971. if (!aht) {
  972. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
  973. return;
  974. }
  975. spl_array_rewind_ex(intern, aht TSRMLS_CC);
  976. }
  977. /* }}} */
  978. static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
  979. {
  980. spl_array_it *iterator = (spl_array_it *)iter;
  981. spl_array_object *object = iterator->object;
  982. if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
  983. zend_user_it_rewind(iter TSRMLS_CC);
  984. } else {
  985. zend_user_it_invalidate_current(iter TSRMLS_CC);
  986. spl_array_rewind(object TSRMLS_CC);
  987. }
  988. }
  989. /* }}} */
  990. /* {{{ spl_array_set_array */
  991. static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
  992. if (Z_TYPE_PP(array) == IS_ARRAY) {
  993. SEPARATE_ZVAL_IF_NOT_REF(array);
  994. }
  995. if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
  996. zval_ptr_dtor(&intern->array);
  997. if (just_array) {
  998. spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
  999. ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
  1000. }
  1001. ar_flags |= SPL_ARRAY_USE_OTHER;
  1002. intern->array = *array;
  1003. } else {
  1004. if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
  1005. zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
  1006. return;
  1007. }
  1008. zval_ptr_dtor(&intern->array);
  1009. intern->array = *array;
  1010. }
  1011. if (object == *array) {
  1012. intern->ar_flags |= SPL_ARRAY_IS_SELF;
  1013. intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
  1014. } else {
  1015. intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
  1016. }
  1017. intern->ar_flags |= ar_flags;
  1018. Z_ADDREF_P(intern->array);
  1019. if (Z_TYPE_PP(array) == IS_OBJECT) {
  1020. zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
  1021. if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
  1022. || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
  1023. zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name);
  1024. }
  1025. }
  1026. spl_array_rewind(intern TSRMLS_CC);
  1027. }
  1028. /* }}} */
  1029. /* iterator handler table */
  1030. zend_object_iterator_funcs spl_array_it_funcs = {
  1031. spl_array_it_dtor,
  1032. spl_array_it_valid,
  1033. spl_array_it_get_current_data,
  1034. spl_array_it_get_current_key,
  1035. spl_array_it_move_forward,
  1036. spl_array_it_rewind
  1037. };
  1038. zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
  1039. {
  1040. spl_array_it *iterator;
  1041. spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1042. if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
  1043. zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
  1044. }
  1045. iterator = emalloc(sizeof(spl_array_it));
  1046. Z_ADDREF_P(object);
  1047. iterator->intern.it.data = (void*)object;
  1048. iterator->intern.it.funcs = &spl_array_it_funcs;
  1049. iterator->intern.ce = ce;
  1050. iterator->intern.value = NULL;
  1051. iterator->object = array_object;
  1052. return (zend_object_iterator*)iterator;
  1053. }
  1054. /* }}} */
  1055. /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
  1056. proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
  1057. Constructs a new array iterator from a path. */
  1058. SPL_METHOD(Array, __construct)
  1059. {
  1060. zval *object = getThis();
  1061. spl_array_object *intern;
  1062. zval **array;
  1063. long ar_flags = 0;
  1064. zend_class_entry *ce_get_iterator = spl_ce_Iterator;
  1065. zend_error_handling error_handling;
  1066. if (ZEND_NUM_ARGS() == 0) {
  1067. return; /* nothing to do */
  1068. }
  1069. zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
  1070. intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1071. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
  1072. zend_restore_error_handling(&error_handling TSRMLS_CC);
  1073. return;
  1074. }
  1075. if (ZEND_NUM_ARGS() > 2) {
  1076. intern->ce_get_iterator = ce_get_iterator;
  1077. }
  1078. ar_flags &= ~SPL_ARRAY_INT_MASK;
  1079. spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
  1080. zend_restore_error_handling(&error_handling TSRMLS_CC);
  1081. }
  1082. /* }}} */
  1083. /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
  1084. Set the class used in getIterator. */
  1085. SPL_METHOD(Array, setIteratorClass)
  1086. {
  1087. zval *object = getThis();
  1088. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1089. zend_class_entry * ce_get_iterator = spl_ce_Iterator;
  1090. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
  1091. return;
  1092. }
  1093. intern->ce_get_iterator = ce_get_iterator;
  1094. }
  1095. /* }}} */
  1096. /* {{{ proto string ArrayObject::getIteratorClass()
  1097. Get the class used in getIterator. */
  1098. SPL_METHOD(Array, getIteratorClass)
  1099. {
  1100. zval *object = getThis();
  1101. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1102. if (zend_parse_parameters_none() == FAILURE) {
  1103. return;
  1104. }
  1105. RETURN_STRING(intern->ce_get_iterator->name, 1);
  1106. }
  1107. /* }}} */
  1108. /* {{{ proto int ArrayObject::getFlags()
  1109. Get flags */
  1110. SPL_METHOD(Array, getFlags)
  1111. {
  1112. zval *object = getThis();
  1113. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1114. if (zend_parse_parameters_none() == FAILURE) {
  1115. return;
  1116. }
  1117. RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
  1118. }
  1119. /* }}} */
  1120. /* {{{ proto void ArrayObject::setFlags(int flags)
  1121. Set flags */
  1122. SPL_METHOD(Array, setFlags)
  1123. {
  1124. zval *object = getThis();
  1125. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1126. long ar_flags = 0;
  1127. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
  1128. return;
  1129. }
  1130. intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
  1131. }
  1132. /* }}} */
  1133. /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
  1134. Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
  1135. SPL_METHOD(Array, exchangeArray)
  1136. {
  1137. zval *object = getThis(), *tmp, **array;
  1138. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1139. array_init(return_value);
  1140. 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*));
  1141. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
  1142. return;
  1143. }
  1144. spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
  1145. }
  1146. /* }}} */
  1147. /* {{{ proto ArrayIterator ArrayObject::getIterator()
  1148. Create a new iterator from a ArrayObject instance */
  1149. SPL_METHOD(Array, getIterator)
  1150. {
  1151. zval *object = getThis();
  1152. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1153. spl_array_object *iterator;
  1154. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1155. if (zend_parse_parameters_none() == FAILURE) {
  1156. return;
  1157. }
  1158. if (!aht) {
  1159. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1160. return;
  1161. }
  1162. return_value->type = IS_OBJECT;
  1163. return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
  1164. Z_SET_REFCOUNT_P(return_value, 1);
  1165. Z_SET_ISREF_P(return_value);
  1166. }
  1167. /* }}} */
  1168. /* {{{ proto void ArrayIterator::rewind()
  1169. Rewind array back to the start */
  1170. SPL_METHOD(Array, rewind)
  1171. {
  1172. zval *object = getThis();
  1173. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1174. if (zend_parse_parameters_none() == FAILURE) {
  1175. return;
  1176. }
  1177. spl_array_rewind(intern TSRMLS_CC);
  1178. }
  1179. /* }}} */
  1180. /* {{{ proto void ArrayIterator::seek(int $position)
  1181. Seek to position. */
  1182. SPL_METHOD(Array, seek)
  1183. {
  1184. long opos, position;
  1185. zval *object = getThis();
  1186. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1187. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1188. int result;
  1189. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
  1190. return;
  1191. }
  1192. if (!aht) {
  1193. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1194. return;
  1195. }
  1196. opos = position;
  1197. if (position >= 0) { /* negative values are not supported */
  1198. spl_array_rewind(intern TSRMLS_CC);
  1199. result = SUCCESS;
  1200. while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
  1201. if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
  1202. return; /* ok */
  1203. }
  1204. }
  1205. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
  1206. } /* }}} */
  1207. int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
  1208. {
  1209. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1210. HashPosition pos;
  1211. if (!aht) {
  1212. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1213. *count = 0;
  1214. return FAILURE;
  1215. }
  1216. if (Z_TYPE_P(intern->array) == IS_OBJECT) {
  1217. /* We need to store the 'pos' since we'll modify it in the functions
  1218. * we're going to call and which do not support 'pos' as parameter. */
  1219. pos = intern->pos;
  1220. *count = 0;
  1221. spl_array_rewind(intern TSRMLS_CC);
  1222. while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
  1223. (*count)++;
  1224. }
  1225. spl_array_set_pos(intern, pos);
  1226. return SUCCESS;
  1227. } else {
  1228. *count = zend_hash_num_elements(aht);
  1229. return SUCCESS;
  1230. }
  1231. } /* }}} */
  1232. int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
  1233. {
  1234. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1235. if (intern->fptr_count) {
  1236. zval *rv;
  1237. zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
  1238. if (rv) {
  1239. zval_ptr_dtor(&intern->retval);
  1240. MAKE_STD_ZVAL(intern->retval);
  1241. ZVAL_ZVAL(intern->retval, rv, 1, 1);
  1242. convert_to_long(intern->retval);
  1243. *count = (long) Z_LVAL_P(intern->retval);
  1244. return SUCCESS;
  1245. }
  1246. *count = 0;
  1247. return FAILURE;
  1248. }
  1249. return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
  1250. } /* }}} */
  1251. /* {{{ proto int ArrayObject::count()
  1252. proto int ArrayIterator::count()
  1253. Return the number of elements in the Iterator. */
  1254. SPL_METHOD(Array, count)
  1255. {
  1256. long count;
  1257. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1258. if (zend_parse_parameters_none() == FAILURE) {
  1259. return;
  1260. }
  1261. spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
  1262. RETURN_LONG(count);
  1263. } /* }}} */
  1264. static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
  1265. {
  1266. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1267. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1268. zval *tmp, *arg = NULL;
  1269. zval *retval_ptr = NULL;
  1270. MAKE_STD_ZVAL(tmp);
  1271. Z_TYPE_P(tmp) = IS_ARRAY;
  1272. Z_ARRVAL_P(tmp) = aht;
  1273. if (!use_arg) {
  1274. aht->nApplyCount++;
  1275. zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
  1276. aht->nApplyCount--;
  1277. } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) {
  1278. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|z", &arg) == FAILURE) {
  1279. Z_TYPE_P(tmp) = IS_NULL;
  1280. zval_ptr_dtor(&tmp);
  1281. zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0 TSRMLS_CC);
  1282. return;
  1283. }
  1284. aht->nApplyCount++;
  1285. zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, arg? 2 : 1, tmp, arg TSRMLS_CC);
  1286. aht->nApplyCount--;
  1287. } else {
  1288. if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
  1289. Z_TYPE_P(tmp) = IS_NULL;
  1290. zval_ptr_dtor(&tmp);
  1291. zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
  1292. return;
  1293. }
  1294. aht->nApplyCount++;
  1295. zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
  1296. aht->nApplyCount--;
  1297. }
  1298. Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
  1299. zval_ptr_dtor(&tmp);
  1300. if (retval_ptr) {
  1301. COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
  1302. }
  1303. } /* }}} */
  1304. #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
  1305. SPL_METHOD(cname, fname) \
  1306. { \
  1307. spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
  1308. }
  1309. /* {{{ proto int ArrayObject::asort([int $sort_flags = SORT_REGULAR ])
  1310. proto int ArrayIterator::asort([int $sort_flags = SORT_REGULAR ])
  1311. Sort the entries by values. */
  1312. SPL_ARRAY_METHOD(Array, asort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
  1313. /* {{{ proto int ArrayObject::ksort([int $sort_flags = SORT_REGULAR ])
  1314. proto int ArrayIterator::ksort([int $sort_flags = SORT_REGULAR ])
  1315. Sort the entries by key. */
  1316. SPL_ARRAY_METHOD(Array, ksort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
  1317. /* {{{ proto int ArrayObject::uasort(callback cmp_function)
  1318. proto int ArrayIterator::uasort(callback cmp_function)
  1319. Sort the entries by values user defined function. */
  1320. SPL_ARRAY_METHOD(Array, uasort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
  1321. /* {{{ proto int ArrayObject::uksort(callback cmp_function)
  1322. proto int ArrayIterator::uksort(callback cmp_function)
  1323. Sort the entries by key using user defined function. */
  1324. SPL_ARRAY_METHOD(Array, uksort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
  1325. /* {{{ proto int ArrayObject::natsort()
  1326. proto int ArrayIterator::natsort()
  1327. Sort the entries by values using "natural order" algorithm. */
  1328. SPL_ARRAY_METHOD(Array, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
  1329. /* {{{ proto int ArrayObject::natcasesort()
  1330. proto int ArrayIterator::natcasesort()
  1331. Sort the entries by key using case insensitive "natural order" algorithm. */
  1332. SPL_ARRAY_METHOD(Array, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
  1333. /* {{{ proto mixed|NULL ArrayIterator::current()
  1334. Return current array entry */
  1335. SPL_METHOD(Array, current)
  1336. {
  1337. zval *object = getThis();
  1338. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1339. zval **entry;
  1340. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1341. if (zend_parse_parameters_none() == FAILURE) {
  1342. return;
  1343. }
  1344. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1345. return;
  1346. }
  1347. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1348. return;
  1349. }
  1350. RETVAL_ZVAL(*entry, 1, 0);
  1351. }
  1352. /* }}} */
  1353. /* {{{ proto mixed|NULL ArrayIterator::key()
  1354. Return current array key */
  1355. SPL_METHOD(Array, key)
  1356. {
  1357. if (zend_parse_parameters_none() == FAILURE) {
  1358. return;
  1359. }
  1360. spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
  1361. } /* }}} */
  1362. void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
  1363. {
  1364. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1365. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1366. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1367. return;
  1368. }
  1369. zend_hash_get_current_key_zval_ex(aht, return_value, &intern->pos);
  1370. }
  1371. /* }}} */
  1372. /* {{{ proto void ArrayIterator::next()
  1373. Move to next entry */
  1374. SPL_METHOD(Array, next)
  1375. {
  1376. zval *object = getThis();
  1377. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1378. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1379. if (zend_parse_parameters_none() == FAILURE) {
  1380. return;
  1381. }
  1382. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1383. return;
  1384. }
  1385. spl_array_next_no_verify(intern, aht TSRMLS_CC);
  1386. }
  1387. /* }}} */
  1388. /* {{{ proto bool ArrayIterator::valid()
  1389. Check whether array contains more entries */
  1390. SPL_METHOD(Array, valid)
  1391. {
  1392. zval *object = getThis();
  1393. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1394. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1395. if (zend_parse_parameters_none() == FAILURE) {
  1396. return;
  1397. }
  1398. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1399. RETURN_FALSE;
  1400. } else {
  1401. RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
  1402. }
  1403. }
  1404. /* }}} */
  1405. /* {{{ proto bool RecursiveArrayIterator::hasChildren()
  1406. Check whether current element has children (e.g. is an array) */
  1407. SPL_METHOD(Array, hasChildren)
  1408. {
  1409. zval *object = getThis(), **entry;
  1410. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1411. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1412. if (zend_parse_parameters_none() == FAILURE) {
  1413. return;
  1414. }
  1415. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1416. RETURN_FALSE;
  1417. }
  1418. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1419. RETURN_FALSE;
  1420. }
  1421. RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
  1422. }
  1423. /* }}} */
  1424. /* {{{ proto object RecursiveArrayIterator::getChildren()
  1425. Create a sub iterator for the current element (same class as $this) */
  1426. SPL_METHOD(Array, getChildren)
  1427. {
  1428. zval *object = getThis(), **entry, *flags;
  1429. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1430. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1431. if (zend_parse_parameters_none() == FAILURE) {
  1432. return;
  1433. }
  1434. if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
  1435. return;
  1436. }
  1437. if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
  1438. return;
  1439. }
  1440. if (Z_TYPE_PP(entry) == IS_OBJECT) {
  1441. if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
  1442. return;
  1443. }
  1444. if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
  1445. RETURN_ZVAL(*entry, 1, 0);
  1446. }
  1447. }
  1448. MAKE_STD_ZVAL(flags);
  1449. ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
  1450. spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
  1451. zval_ptr_dtor(&flags);
  1452. }
  1453. /* }}} */
  1454. /* {{{ proto string ArrayObject::serialize()
  1455. Serialize the object */
  1456. SPL_METHOD(Array, serialize)
  1457. {
  1458. zval *object = getThis();
  1459. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
  1460. HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1461. zval members, *pmembers;
  1462. php_serialize_data_t var_hash;
  1463. smart_str buf = {0};
  1464. zval *flags;
  1465. if (zend_parse_parameters_none() == FAILURE) {
  1466. return;
  1467. }
  1468. if (!aht) {
  1469. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
  1470. return;
  1471. }
  1472. PHP_VAR_SERIALIZE_INIT(var_hash);
  1473. MAKE_STD_ZVAL(flags);
  1474. ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
  1475. /* storage */
  1476. smart_str_appendl(&buf, "x:", 2);
  1477. php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
  1478. zval_ptr_dtor(&flags);
  1479. if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
  1480. php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC);
  1481. smart_str_appendc(&buf, ';');
  1482. }
  1483. /* members */
  1484. smart_str_appendl(&buf, "m:", 2);
  1485. INIT_PZVAL(&members);
  1486. if (!intern->std.properties) {
  1487. rebuild_object_properties(&intern->std);
  1488. }
  1489. Z_ARRVAL(members) = intern->std.properties;
  1490. Z_TYPE(members) = IS_ARRAY;
  1491. pmembers = &members;
  1492. php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
  1493. /* done */
  1494. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  1495. if (buf.c) {
  1496. RETURN_STRINGL(buf.c, buf.len, 0);
  1497. }
  1498. RETURN_NULL();
  1499. } /* }}} */
  1500. /* {{{ proto void ArrayObject::unserialize(string serialized)
  1501. * unserialize the object
  1502. */
  1503. SPL_METHOD(Array, unserialize)
  1504. {
  1505. spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1506. char *buf;
  1507. int buf_len;
  1508. const unsigned char *p, *s;
  1509. php_unserialize_data_t var_hash;
  1510. zval *pmembers, *pflags = NULL;
  1511. HashTable *aht;
  1512. long flags;
  1513. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
  1514. return;
  1515. }
  1516. if (buf_len == 0) {
  1517. return;
  1518. }
  1519. aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
  1520. if (aht->nApplyCount > 0) {
  1521. zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
  1522. return;
  1523. }
  1524. /* storage */
  1525. s = p = (const unsigned char*)buf;
  1526. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  1527. if (*p!= 'x' || *++p != ':') {
  1528. goto outexcept;
  1529. }
  1530. ++p;
  1531. ALLOC_INIT_ZVAL(pflags);
  1532. if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
  1533. goto outexcept;
  1534. }
  1535. var_push_dtor(&var_hash, &pflags);
  1536. --p; /* for ';' */
  1537. flags = Z_LVAL_P(pflags);
  1538. /* flags needs to be verified and we also need to verify whether the next
  1539. * thing we get is ';'. After that we require an 'm' or somethign else
  1540. * where 'm' stands for members and anything else should be an array. If
  1541. * neither 'a' or 'm' follows we have an error. */
  1542. if (*p != ';') {
  1543. goto outexcept;
  1544. }
  1545. ++p;
  1546. if (*p!='m') {
  1547. if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
  1548. goto outexcept;
  1549. }
  1550. intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
  1551. intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
  1552. zval_ptr_dtor(&intern->array);
  1553. ALLOC_INIT_ZVAL(intern->array);
  1554. if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)
  1555. || (Z_TYPE_P(intern->array) != IS_ARRAY && Z_TYPE_P(intern->array) != IS_OBJECT)) {
  1556. // zval_ptr_dtor(&intern->array);
  1557. goto outexcept;
  1558. }
  1559. var_push_dtor(&var_hash, &intern->array);
  1560. }
  1561. if (*p != ';') {
  1562. goto outexcept;
  1563. }
  1564. ++p;
  1565. /* members */
  1566. if (*p!= 'm' || *++p != ':') {
  1567. goto outexcept;
  1568. }
  1569. ++p;
  1570. ALLOC_INIT_ZVAL(pmembers);
  1571. if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pmembers) != IS_ARRAY) {
  1572. zval_ptr_dtor(&pmembers);
  1573. goto outexcept;
  1574. }
  1575. var_push_dtor(&var_hash, &pmembers);
  1576. /* copy members */
  1577. if (!intern->std.properties) {
  1578. rebuild_object_properties(&intern->std);
  1579. }
  1580. zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
  1581. zval_ptr_dtor(&pmembers);
  1582. /* done reading $serialized */
  1583. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  1584. if (pflags) {
  1585. zval_ptr_dtor(&pflags);
  1586. }
  1587. return;
  1588. outexcept:
  1589. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  1590. if (pflags) {
  1591. zval_ptr_dtor(&pflags);
  1592. }
  1593. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
  1594. return;
  1595. } /* }}} */
  1596. /* {{{ arginfo and function table */
  1597. ZEND_BEGIN_ARG_INFO_EX(arginfo_array___construct, 0, 0, 0)
  1598. ZEND_ARG_INFO(0, array)
  1599. ZEND_END_ARG_INFO()
  1600. ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
  1601. ZEND_ARG_INFO(0, index)
  1602. ZEND_END_ARG_INFO()
  1603. ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
  1604. ZEND_ARG_INFO(0, index)
  1605. ZEND_ARG_INFO(0, newval)
  1606. ZEND_END_ARG_INFO()
  1607. ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
  1608. ZEND_ARG_INFO(0, value)
  1609. ZEND_END_ARG_INFO()
  1610. ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
  1611. ZEND_ARG_INFO(0, position)
  1612. ZEND_END_ARG_INFO()
  1613. ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
  1614. ZEND_ARG_INFO(0, array)
  1615. ZEND_END_ARG_INFO()
  1616. ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
  1617. ZEND_ARG_INFO(0, flags)
  1618. ZEND_END_ARG_INFO()
  1619. ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
  1620. ZEND_ARG_INFO(0, iteratorClass)
  1621. ZEND_END_ARG_INFO()
  1622. ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
  1623. ZEND_ARG_INFO(0, cmp_function)
  1624. ZEND_END_ARG_INFO();
  1625. ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
  1626. ZEND_ARG_INFO(0, serialized)
  1627. ZEND_END_ARG_INFO();
  1628. ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
  1629. ZEND_END_ARG_INFO()
  1630. static const zend_function_entry spl_funcs_ArrayObject[] = {
  1631. SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
  1632. SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1633. SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1634. SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
  1635. SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1636. SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
  1637. SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
  1638. SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
  1639. SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
  1640. SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
  1641. SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1642. SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1643. SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1644. SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1645. SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1646. SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1647. SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
  1648. SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
  1649. /* ArrayObject specific */
  1650. SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC)
  1651. SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
  1652. SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
  1653. SPL_ME(Array, getIteratorClass, arginfo_array_void, ZEND_ACC_PUBLIC)
  1654. PHP_FE_END
  1655. };
  1656. static const zend_function_entry spl_funcs_ArrayIterator[] = {
  1657. SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
  1658. SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1659. SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1660. SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
  1661. SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
  1662. SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
  1663. SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
  1664. SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
  1665. SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
  1666. SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
  1667. SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1668. SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1669. SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1670. SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
  1671. SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1672. SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
  1673. SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
  1674. SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
  1675. /* ArrayIterator specific */
  1676. SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC)
  1677. SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC)
  1678. SPL_ME(Array, key, arginfo_array_void, ZEND_ACC_PUBLIC)
  1679. SPL_ME(Array, next, arginfo_array_void, ZEND_ACC_PUBLIC)
  1680. SPL_ME(Array, valid, arginfo_array_void, ZEND_ACC_PUBLIC)
  1681. SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
  1682. PHP_FE_END
  1683. };
  1684. static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
  1685. SPL_ME(Array, hasChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
  1686. SPL_ME(Array, getChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
  1687. PHP_FE_END
  1688. };
  1689. /* }}} */
  1690. /* {{{ PHP_MINIT_FUNCTION(spl_array) */
  1691. PHP_MINIT_FUNCTION(spl_array)
  1692. {
  1693. REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
  1694. REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
  1695. REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
  1696. REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
  1697. REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
  1698. memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
  1699. spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
  1700. spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
  1701. spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
  1702. spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
  1703. spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
  1704. spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
  1705. spl_handler_ArrayObject.get_properties = spl_array_get_properties;
  1706. spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
  1707. spl_handler_ArrayObject.get_gc = spl_array_get_gc;
  1708. spl_handler_ArrayObject.read_property = spl_array_read_property;
  1709. spl_handler_ArrayObject.write_property = spl_array_write_property;
  1710. spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
  1711. spl_handler_ArrayObject.has_property = spl_array_has_property;
  1712. spl_handler_ArrayObject.unset_property = spl_array_unset_property;
  1713. spl_handler_ArrayObject.compare_objects = spl_array_compare_objects;
  1714. REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
  1715. REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
  1716. REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
  1717. REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
  1718. REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
  1719. REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
  1720. memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
  1721. spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
  1722. REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
  1723. REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
  1724. spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
  1725. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1726. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1727. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1728. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1729. REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
  1730. return SUCCESS;
  1731. }
  1732. /* }}} */
  1733. /*
  1734. * Local variables:
  1735. * tab-width: 4
  1736. * c-basic-offset: 4
  1737. * End:
  1738. * vim600: fdm=marker
  1739. * vim: noet sw=4 ts=4
  1740. */