spl_array.c 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. # include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "ext/standard/info.h"
  22. #include "ext/standard/php_var.h"
  23. #include "zend_smart_str.h"
  24. #include "zend_interfaces.h"
  25. #include "zend_exceptions.h"
  26. #include "php_spl.h"
  27. #include "spl_array_arginfo.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. #define SPL_ARRAY_STD_PROP_LIST 0x00000001
  39. #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
  40. #define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004
  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_SELF 0x01000000
  47. #define SPL_ARRAY_USE_OTHER 0x02000000
  48. #define SPL_ARRAY_INT_MASK 0xFFFF0000
  49. #define SPL_ARRAY_CLONE_MASK 0x0100FFFF
  50. #define SPL_ARRAY_METHOD_NO_ARG 0
  51. #define SPL_ARRAY_METHOD_CALLBACK_ARG 1
  52. #define SPL_ARRAY_METHOD_SORT_FLAGS_ARG 2
  53. typedef struct _spl_array_object {
  54. zval array;
  55. uint32_t ht_iter;
  56. int ar_flags;
  57. unsigned char nApplyCount;
  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_function *fptr_count;
  63. zend_class_entry* ce_get_iterator;
  64. zend_object std;
  65. } spl_array_object;
  66. static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
  67. return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std));
  68. }
  69. /* }}} */
  70. #define Z_SPLARRAY_P(zv) spl_array_from_obj(Z_OBJ_P((zv)))
  71. static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) { /* {{{ */
  72. //??? TODO: Delay duplication for arrays; only duplicate for write operations
  73. if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
  74. if (!intern->std.properties) {
  75. rebuild_object_properties(&intern->std);
  76. }
  77. return &intern->std.properties;
  78. } else if (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
  79. spl_array_object *other = Z_SPLARRAY_P(&intern->array);
  80. return spl_array_get_hash_table_ptr(other);
  81. } else if (Z_TYPE(intern->array) == IS_ARRAY) {
  82. return &Z_ARRVAL(intern->array);
  83. } else {
  84. zend_object *obj = Z_OBJ(intern->array);
  85. if (!obj->properties) {
  86. rebuild_object_properties(obj);
  87. } else if (GC_REFCOUNT(obj->properties) > 1) {
  88. if (EXPECTED(!(GC_FLAGS(obj->properties) & IS_ARRAY_IMMUTABLE))) {
  89. GC_DELREF(obj->properties);
  90. }
  91. obj->properties = zend_array_dup(obj->properties);
  92. }
  93. return &obj->properties;
  94. }
  95. }
  96. /* }}} */
  97. static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */
  98. return *spl_array_get_hash_table_ptr(intern);
  99. }
  100. /* }}} */
  101. static inline bool spl_array_is_object(spl_array_object *intern) /* {{{ */
  102. {
  103. while (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
  104. intern = Z_SPLARRAY_P(&intern->array);
  105. }
  106. return (intern->ar_flags & SPL_ARRAY_IS_SELF) || Z_TYPE(intern->array) == IS_OBJECT;
  107. }
  108. /* }}} */
  109. static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht);
  110. static zend_never_inline void spl_array_create_ht_iter(HashTable *ht, spl_array_object* intern) /* {{{ */
  111. {
  112. intern->ht_iter = zend_hash_iterator_add(ht, zend_hash_get_current_pos(ht));
  113. zend_hash_internal_pointer_reset_ex(ht, &EG(ht_iterators)[intern->ht_iter].pos);
  114. spl_array_skip_protected(intern, ht);
  115. }
  116. /* }}} */
  117. static zend_always_inline uint32_t *spl_array_get_pos_ptr(HashTable *ht, spl_array_object* intern) /* {{{ */
  118. {
  119. if (UNEXPECTED(intern->ht_iter == (uint32_t)-1)) {
  120. spl_array_create_ht_iter(ht, intern);
  121. }
  122. return &EG(ht_iterators)[intern->ht_iter].pos;
  123. }
  124. /* }}} */
  125. /* {{{ spl_array_object_free_storage */
  126. static void spl_array_object_free_storage(zend_object *object)
  127. {
  128. spl_array_object *intern = spl_array_from_obj(object);
  129. if (intern->ht_iter != (uint32_t) -1) {
  130. zend_hash_iterator_del(intern->ht_iter);
  131. }
  132. zend_object_std_dtor(&intern->std);
  133. zval_ptr_dtor(&intern->array);
  134. }
  135. /* }}} */
  136. /* {{{ spl_array_object_new_ex */
  137. static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_object *orig, int clone_orig)
  138. {
  139. spl_array_object *intern;
  140. zend_class_entry *parent = class_type;
  141. int inherited = 0;
  142. intern = zend_object_alloc(sizeof(spl_array_object), parent);
  143. zend_object_std_init(&intern->std, class_type);
  144. object_properties_init(&intern->std, class_type);
  145. intern->ar_flags = 0;
  146. intern->ce_get_iterator = spl_ce_ArrayIterator;
  147. if (orig) {
  148. spl_array_object *other = spl_array_from_obj(orig);
  149. intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
  150. intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
  151. intern->ce_get_iterator = other->ce_get_iterator;
  152. if (clone_orig) {
  153. if (other->ar_flags & SPL_ARRAY_IS_SELF) {
  154. ZVAL_UNDEF(&intern->array);
  155. } else if (orig->handlers == &spl_handler_ArrayObject) {
  156. ZVAL_ARR(&intern->array,
  157. zend_array_dup(spl_array_get_hash_table(other)));
  158. } else {
  159. ZEND_ASSERT(orig->handlers == &spl_handler_ArrayIterator);
  160. ZVAL_OBJ_COPY(&intern->array, orig);
  161. intern->ar_flags |= SPL_ARRAY_USE_OTHER;
  162. }
  163. } else {
  164. ZVAL_OBJ_COPY(&intern->array, orig);
  165. intern->ar_flags |= SPL_ARRAY_USE_OTHER;
  166. }
  167. } else {
  168. array_init(&intern->array);
  169. }
  170. while (parent) {
  171. if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
  172. intern->std.handlers = &spl_handler_ArrayIterator;
  173. break;
  174. } else if (parent == spl_ce_ArrayObject) {
  175. intern->std.handlers = &spl_handler_ArrayObject;
  176. break;
  177. }
  178. parent = parent->parent;
  179. inherited = 1;
  180. }
  181. ZEND_ASSERT(parent);
  182. if (inherited) {
  183. intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
  184. if (intern->fptr_offset_get->common.scope == parent) {
  185. intern->fptr_offset_get = NULL;
  186. }
  187. intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
  188. if (intern->fptr_offset_set->common.scope == parent) {
  189. intern->fptr_offset_set = NULL;
  190. }
  191. intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
  192. if (intern->fptr_offset_has->common.scope == parent) {
  193. intern->fptr_offset_has = NULL;
  194. }
  195. intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
  196. if (intern->fptr_offset_del->common.scope == parent) {
  197. intern->fptr_offset_del = NULL;
  198. }
  199. intern->fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
  200. if (intern->fptr_count->common.scope == parent) {
  201. intern->fptr_count = NULL;
  202. }
  203. }
  204. /* Cache iterator functions if ArrayIterator or derived. Check current's */
  205. /* cache since only current is always required */
  206. if (intern->std.handlers == &spl_handler_ArrayIterator) {
  207. zend_class_iterator_funcs *funcs_ptr = class_type->iterator_funcs_ptr;
  208. if (!funcs_ptr->zf_current) {
  209. funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
  210. funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
  211. funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
  212. funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
  213. funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
  214. }
  215. if (inherited) {
  216. if (funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
  217. if (funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
  218. if (funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
  219. if (funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
  220. if (funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
  221. }
  222. }
  223. intern->ht_iter = (uint32_t)-1;
  224. return &intern->std;
  225. }
  226. /* }}} */
  227. /* {{{ spl_array_object_new */
  228. static zend_object *spl_array_object_new(zend_class_entry *class_type)
  229. {
  230. return spl_array_object_new_ex(class_type, NULL, 0);
  231. }
  232. /* }}} */
  233. /* {{{ spl_array_object_clone */
  234. static zend_object *spl_array_object_clone(zend_object *old_object)
  235. {
  236. zend_object *new_object;
  237. new_object = spl_array_object_new_ex(old_object->ce, old_object, 1);
  238. zend_objects_clone_members(new_object, old_object);
  239. return new_object;
  240. }
  241. /* }}} */
  242. typedef struct {
  243. zend_string *key;
  244. zend_ulong h;
  245. bool release_key;
  246. } spl_hash_key;
  247. static void spl_hash_key_release(spl_hash_key *key) {
  248. if (key->release_key) {
  249. zend_string_release_ex(key->key, 0);
  250. }
  251. }
  252. static zend_result get_hash_key(spl_hash_key *key, spl_array_object *intern, zval *offset)
  253. {
  254. key->release_key = false;
  255. try_again:
  256. switch (Z_TYPE_P(offset)) {
  257. case IS_NULL:
  258. key->key = ZSTR_EMPTY_ALLOC();
  259. return SUCCESS;
  260. case IS_STRING:
  261. key->key = Z_STR_P(offset);
  262. if (ZEND_HANDLE_NUMERIC(key->key, key->h)) {
  263. key->key = NULL;
  264. break;
  265. }
  266. return SUCCESS;
  267. case IS_RESOURCE:
  268. zend_use_resource_as_offset(offset);
  269. key->key = NULL;
  270. key->h = Z_RES_P(offset)->handle;
  271. break;
  272. case IS_DOUBLE:
  273. key->key = NULL;
  274. key->h = zend_dval_to_lval_safe(Z_DVAL_P(offset));
  275. break;
  276. case IS_FALSE:
  277. key->key = NULL;
  278. key->h = 0;
  279. break;
  280. case IS_TRUE:
  281. key->key = NULL;
  282. key->h = 1;
  283. break;
  284. case IS_LONG:
  285. key->key = NULL;
  286. key->h = Z_LVAL_P(offset);
  287. break;
  288. case IS_REFERENCE:
  289. ZVAL_DEREF(offset);
  290. goto try_again;
  291. default:
  292. zend_type_error("Illegal offset type");
  293. return FAILURE;
  294. }
  295. if (spl_array_is_object(intern)) {
  296. key->key = zend_long_to_str(key->h);
  297. key->release_key = true;
  298. }
  299. return SUCCESS;
  300. }
  301. static zval *spl_array_get_dimension_ptr(int check_inherited, spl_array_object *intern, zval *offset, int type) /* {{{ */
  302. {
  303. zval *retval;
  304. spl_hash_key key;
  305. HashTable *ht = spl_array_get_hash_table(intern);
  306. if (!offset || Z_ISUNDEF_P(offset) || !ht) {
  307. return &EG(uninitialized_zval);
  308. }
  309. if ((type == BP_VAR_W || type == BP_VAR_RW) && intern->nApplyCount > 0) {
  310. zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
  311. return &EG(error_zval);
  312. }
  313. if (get_hash_key(&key, intern, offset) == FAILURE) {
  314. zend_type_error("Illegal offset type");
  315. return (type == BP_VAR_W || type == BP_VAR_RW) ?
  316. &EG(error_zval) : &EG(uninitialized_zval);
  317. }
  318. if (key.key) {
  319. retval = zend_hash_find(ht, key.key);
  320. if (retval) {
  321. if (Z_TYPE_P(retval) == IS_INDIRECT) {
  322. retval = Z_INDIRECT_P(retval);
  323. if (Z_TYPE_P(retval) == IS_UNDEF) {
  324. switch (type) {
  325. case BP_VAR_R:
  326. zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key.key));
  327. ZEND_FALLTHROUGH;
  328. case BP_VAR_UNSET:
  329. case BP_VAR_IS:
  330. retval = &EG(uninitialized_zval);
  331. break;
  332. case BP_VAR_RW:
  333. zend_error(E_WARNING,"Undefined array key \"%s\"", ZSTR_VAL(key.key));
  334. ZEND_FALLTHROUGH;
  335. case BP_VAR_W: {
  336. ZVAL_NULL(retval);
  337. }
  338. }
  339. }
  340. }
  341. } else {
  342. switch (type) {
  343. case BP_VAR_R:
  344. zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key.key));
  345. ZEND_FALLTHROUGH;
  346. case BP_VAR_UNSET:
  347. case BP_VAR_IS:
  348. retval = &EG(uninitialized_zval);
  349. break;
  350. case BP_VAR_RW:
  351. zend_error(E_WARNING,"Undefined array key \"%s\"", ZSTR_VAL(key.key));
  352. ZEND_FALLTHROUGH;
  353. case BP_VAR_W: {
  354. zval value;
  355. ZVAL_NULL(&value);
  356. retval = zend_hash_update(ht, key.key, &value);
  357. }
  358. }
  359. }
  360. spl_hash_key_release(&key);
  361. } else {
  362. if ((retval = zend_hash_index_find(ht, key.h)) == NULL) {
  363. switch (type) {
  364. case BP_VAR_R:
  365. zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, key.h);
  366. ZEND_FALLTHROUGH;
  367. case BP_VAR_UNSET:
  368. case BP_VAR_IS:
  369. retval = &EG(uninitialized_zval);
  370. break;
  371. case BP_VAR_RW:
  372. zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, key.h);
  373. ZEND_FALLTHROUGH;
  374. case BP_VAR_W: {
  375. zval value;
  376. ZVAL_NULL(&value);
  377. retval = zend_hash_index_update(ht, key.h, &value);
  378. }
  379. }
  380. }
  381. }
  382. return retval;
  383. } /* }}} */
  384. static int spl_array_has_dimension(zend_object *object, zval *offset, int check_empty);
  385. static zval *spl_array_read_dimension_ex(int check_inherited, zend_object *object, zval *offset, int type, zval *rv) /* {{{ */
  386. {
  387. spl_array_object *intern = spl_array_from_obj(object);
  388. zval *ret;
  389. if (check_inherited &&
  390. (intern->fptr_offset_get || (type == BP_VAR_IS && intern->fptr_offset_has))) {
  391. if (type == BP_VAR_IS) {
  392. if (!spl_array_has_dimension(object, offset, 0)) {
  393. return &EG(uninitialized_zval);
  394. }
  395. }
  396. if (intern->fptr_offset_get) {
  397. zval tmp;
  398. if (!offset) {
  399. ZVAL_UNDEF(&tmp);
  400. offset = &tmp;
  401. }
  402. zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_get, "offsetGet", rv, offset);
  403. if (!Z_ISUNDEF_P(rv)) {
  404. return rv;
  405. }
  406. return &EG(uninitialized_zval);
  407. }
  408. }
  409. ret = spl_array_get_dimension_ptr(check_inherited, intern, offset, type);
  410. /* When in a write context,
  411. * ZE has to be fooled into thinking this is in a reference set
  412. * by separating (if necessary) and returning as IS_REFERENCE (with refcount == 1)
  413. */
  414. if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) &&
  415. !Z_ISREF_P(ret) &&
  416. EXPECTED(ret != &EG(uninitialized_zval))) {
  417. ZVAL_NEW_REF(ret, ret);
  418. }
  419. return ret;
  420. } /* }}} */
  421. static zval *spl_array_read_dimension(zend_object *object, zval *offset, int type, zval *rv) /* {{{ */
  422. {
  423. return spl_array_read_dimension_ex(1, object, offset, type, rv);
  424. } /* }}} */
  425. static void spl_array_write_dimension_ex(int check_inherited, zend_object *object, zval *offset, zval *value) /* {{{ */
  426. {
  427. spl_array_object *intern = spl_array_from_obj(object);
  428. HashTable *ht;
  429. spl_hash_key key;
  430. if (check_inherited && intern->fptr_offset_set) {
  431. zval tmp;
  432. if (!offset) {
  433. ZVAL_NULL(&tmp);
  434. offset = &tmp;
  435. }
  436. zend_call_method_with_2_params(object, object->ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
  437. return;
  438. }
  439. if (intern->nApplyCount > 0) {
  440. zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
  441. return;
  442. }
  443. Z_TRY_ADDREF_P(value);
  444. if (!offset || Z_TYPE_P(offset) == IS_NULL) {
  445. ht = spl_array_get_hash_table(intern);
  446. zend_hash_next_index_insert(ht, value);
  447. return;
  448. }
  449. if (get_hash_key(&key, intern, offset) == FAILURE) {
  450. zend_type_error("Illegal offset type");
  451. zval_ptr_dtor(value);
  452. return;
  453. }
  454. ht = spl_array_get_hash_table(intern);
  455. if (key.key) {
  456. zend_hash_update_ind(ht, key.key, value);
  457. spl_hash_key_release(&key);
  458. } else {
  459. zend_hash_index_update(ht, key.h, value);
  460. }
  461. } /* }}} */
  462. static void spl_array_write_dimension(zend_object *object, zval *offset, zval *value) /* {{{ */
  463. {
  464. spl_array_write_dimension_ex(1, object, offset, value);
  465. } /* }}} */
  466. static void spl_array_unset_dimension_ex(int check_inherited, zend_object *object, zval *offset) /* {{{ */
  467. {
  468. HashTable *ht;
  469. spl_array_object *intern = spl_array_from_obj(object);
  470. spl_hash_key key;
  471. if (check_inherited && intern->fptr_offset_del) {
  472. zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
  473. return;
  474. }
  475. if (intern->nApplyCount > 0) {
  476. zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
  477. return;
  478. }
  479. if (get_hash_key(&key, intern, offset) == FAILURE) {
  480. zend_type_error("Illegal offset type in unset");
  481. return;
  482. }
  483. ht = spl_array_get_hash_table(intern);
  484. if (key.key) {
  485. zval *data = zend_hash_find(ht, key.key);
  486. if (data) {
  487. if (Z_TYPE_P(data) == IS_INDIRECT) {
  488. data = Z_INDIRECT_P(data);
  489. if (Z_TYPE_P(data) != IS_UNDEF) {
  490. zval_ptr_dtor(data);
  491. ZVAL_UNDEF(data);
  492. HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
  493. zend_hash_move_forward_ex(ht, spl_array_get_pos_ptr(ht, intern));
  494. if (spl_array_is_object(intern)) {
  495. spl_array_skip_protected(intern, ht);
  496. }
  497. }
  498. } else {
  499. zend_hash_del(ht, key.key);
  500. }
  501. }
  502. spl_hash_key_release(&key);
  503. } else {
  504. zend_hash_index_del(ht, key.h);
  505. }
  506. } /* }}} */
  507. static void spl_array_unset_dimension(zend_object *object, zval *offset) /* {{{ */
  508. {
  509. spl_array_unset_dimension_ex(1, object, offset);
  510. } /* }}} */
  511. static int spl_array_has_dimension_ex(bool check_inherited, zend_object *object, zval *offset, int check_empty) /* {{{ */
  512. {
  513. spl_array_object *intern = spl_array_from_obj(object);
  514. zval rv, *value = NULL, *tmp;
  515. if (check_inherited && intern->fptr_offset_has) {
  516. zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
  517. if (!zend_is_true(&rv)) {
  518. zval_ptr_dtor(&rv);
  519. return 0;
  520. }
  521. zval_ptr_dtor(&rv);
  522. /* For isset calls we don't need to check the value, so return early */
  523. if (!check_empty) {
  524. return 1;
  525. } else if (intern->fptr_offset_get) {
  526. value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R, &rv);
  527. }
  528. }
  529. if (!value) {
  530. HashTable *ht = spl_array_get_hash_table(intern);
  531. spl_hash_key key;
  532. if (get_hash_key(&key, intern, offset) == FAILURE) {
  533. zend_type_error("Illegal offset type in isset or empty");
  534. return 0;
  535. }
  536. if (key.key) {
  537. tmp = zend_hash_find(ht, key.key);
  538. spl_hash_key_release(&key);
  539. } else {
  540. tmp = zend_hash_index_find(ht, key.h);
  541. }
  542. if (!tmp) {
  543. return 0;
  544. }
  545. /* check_empty is only equal to 2 if it is called from offsetExists on this class,
  546. * where it needs to report an offset exists even if the value is null */
  547. if (check_empty == 2) {
  548. return 1;
  549. }
  550. if (check_empty && check_inherited && intern->fptr_offset_get) {
  551. value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R, &rv);
  552. } else {
  553. value = tmp;
  554. }
  555. }
  556. if (value == &rv) {
  557. zval_ptr_dtor(&rv);
  558. }
  559. /* empty() check the value is not falsy, isset() only check it is not null */
  560. return check_empty ? zend_is_true(value) : Z_TYPE_P(value) != IS_NULL;
  561. } /* }}} */
  562. static int spl_array_has_dimension(zend_object *object, zval *offset, int check_empty) /* {{{ */
  563. {
  564. return spl_array_has_dimension_ex(/* check_inherited */ true, object, offset, check_empty);
  565. } /* }}} */
  566. /* {{{ Returns whether the requested $index exists. */
  567. PHP_METHOD(ArrayObject, offsetExists)
  568. {
  569. zval *index;
  570. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
  571. RETURN_THROWS();
  572. }
  573. RETURN_BOOL(spl_array_has_dimension_ex(/* check_inherited */ false, Z_OBJ_P(ZEND_THIS), index, 2));
  574. } /* }}} */
  575. /* {{{ Returns the value at the specified $index. */
  576. PHP_METHOD(ArrayObject, offsetGet)
  577. {
  578. zval *value, *index;
  579. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
  580. RETURN_THROWS();
  581. }
  582. value = spl_array_read_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, BP_VAR_R, return_value);
  583. if (value != return_value) {
  584. RETURN_COPY_DEREF(value);
  585. }
  586. } /* }}} */
  587. /* {{{ Sets the value at the specified $index to $newval. */
  588. PHP_METHOD(ArrayObject, offsetSet)
  589. {
  590. zval *index, *value;
  591. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &index, &value) == FAILURE) {
  592. RETURN_THROWS();
  593. }
  594. spl_array_write_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, value);
  595. } /* }}} */
  596. void spl_array_iterator_append(zval *object, zval *append_value) /* {{{ */
  597. {
  598. spl_array_object *intern = Z_SPLARRAY_P(object);
  599. if (spl_array_is_object(intern)) {
  600. zend_throw_error(NULL, "Cannot append properties to objects, use %s::offsetSet() instead", ZSTR_VAL(Z_OBJCE_P(object)->name));
  601. return;
  602. }
  603. spl_array_write_dimension(Z_OBJ_P(object), NULL, append_value);
  604. } /* }}} */
  605. /* {{{ Appends the value (cannot be called for objects). */
  606. PHP_METHOD(ArrayObject, append)
  607. {
  608. zval *value;
  609. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
  610. RETURN_THROWS();
  611. }
  612. spl_array_iterator_append(ZEND_THIS, value);
  613. } /* }}} */
  614. /* {{{ Unsets the value at the specified $index. */
  615. PHP_METHOD(ArrayObject, offsetUnset)
  616. {
  617. zval *index;
  618. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
  619. RETURN_THROWS();
  620. }
  621. spl_array_unset_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index);
  622. } /* }}} */
  623. /* {{{ Return a copy of the contained array */
  624. PHP_METHOD(ArrayObject, getArrayCopy)
  625. {
  626. zval *object = ZEND_THIS;
  627. spl_array_object *intern = Z_SPLARRAY_P(object);
  628. if (zend_parse_parameters_none() == FAILURE) {
  629. RETURN_THROWS();
  630. }
  631. RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
  632. } /* }}} */
  633. static HashTable *spl_array_get_properties_for(zend_object *object, zend_prop_purpose purpose) /* {{{ */
  634. {
  635. spl_array_object *intern = spl_array_from_obj(object);
  636. HashTable *ht;
  637. bool dup;
  638. if (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) {
  639. return zend_std_get_properties_for(object, purpose);
  640. }
  641. /* We are supposed to be the only owner of the internal hashtable.
  642. * The "dup" flag decides whether this is a "long-term" use where
  643. * we need to duplicate, or a "temporary" one, where we can expect
  644. * that no operations on the ArrayObject will be performed in the
  645. * meantime. */
  646. switch (purpose) {
  647. case ZEND_PROP_PURPOSE_ARRAY_CAST:
  648. dup = 1;
  649. break;
  650. case ZEND_PROP_PURPOSE_VAR_EXPORT:
  651. case ZEND_PROP_PURPOSE_JSON:
  652. dup = 0;
  653. break;
  654. default:
  655. return zend_std_get_properties_for(object, purpose);
  656. }
  657. ht = spl_array_get_hash_table(intern);
  658. if (dup) {
  659. ht = zend_array_dup(ht);
  660. } else {
  661. GC_ADDREF(ht);
  662. }
  663. return ht;
  664. } /* }}} */
  665. static inline HashTable* spl_array_get_debug_info(zend_object *obj) /* {{{ */
  666. {
  667. zval *storage;
  668. zend_string *zname;
  669. zend_class_entry *base;
  670. spl_array_object *intern = spl_array_from_obj(obj);
  671. if (!intern->std.properties) {
  672. rebuild_object_properties(&intern->std);
  673. }
  674. if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
  675. return zend_array_dup(intern->std.properties);
  676. } else {
  677. HashTable *debug_info;
  678. debug_info = zend_new_array(zend_hash_num_elements(intern->std.properties) + 1);
  679. zend_hash_copy(debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref);
  680. storage = &intern->array;
  681. Z_TRY_ADDREF_P(storage);
  682. base = obj->handlers == &spl_handler_ArrayIterator
  683. ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
  684. zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1);
  685. zend_symtable_update(debug_info, zname, storage);
  686. zend_string_release_ex(zname, 0);
  687. return debug_info;
  688. }
  689. }
  690. /* }}} */
  691. static HashTable *spl_array_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
  692. {
  693. spl_array_object *intern = spl_array_from_obj(obj);
  694. *gc_data = &intern->array;
  695. *gc_data_count = 1;
  696. return zend_std_get_properties(obj);
  697. }
  698. /* }}} */
  699. static zval *spl_array_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
  700. {
  701. spl_array_object *intern = spl_array_from_obj(object);
  702. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  703. && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) {
  704. zval member;
  705. ZVAL_STR(&member, name);
  706. return spl_array_read_dimension(object, &member, type, rv);
  707. }
  708. return zend_std_read_property(object, name, type, cache_slot, rv);
  709. } /* }}} */
  710. static zval *spl_array_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot) /* {{{ */
  711. {
  712. spl_array_object *intern = spl_array_from_obj(object);
  713. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  714. && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) {
  715. zval member;
  716. ZVAL_STR(&member, name);
  717. spl_array_write_dimension(object, &member, value);
  718. return value;
  719. }
  720. return zend_std_write_property(object, name, value, cache_slot);
  721. } /* }}} */
  722. static zval *spl_array_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
  723. {
  724. spl_array_object *intern = spl_array_from_obj(object);
  725. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  726. && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) {
  727. /* If object has offsetGet() overridden, then fallback to read_property,
  728. * which will call offsetGet(). */
  729. zval member;
  730. if (intern->fptr_offset_get) {
  731. return NULL;
  732. }
  733. ZVAL_STR(&member, name);
  734. return spl_array_get_dimension_ptr(1, intern, &member, type);
  735. }
  736. return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
  737. } /* }}} */
  738. static int spl_array_has_property(zend_object *object, zend_string *name, int has_set_exists, void **cache_slot) /* {{{ */
  739. {
  740. spl_array_object *intern = spl_array_from_obj(object);
  741. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  742. && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) {
  743. zval member;
  744. ZVAL_STR(&member, name);
  745. return spl_array_has_dimension(object, &member, has_set_exists);
  746. }
  747. return zend_std_has_property(object, name, has_set_exists, cache_slot);
  748. } /* }}} */
  749. static void spl_array_unset_property(zend_object *object, zend_string *name, void **cache_slot) /* {{{ */
  750. {
  751. spl_array_object *intern = spl_array_from_obj(object);
  752. if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
  753. && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) {
  754. zval member;
  755. ZVAL_STR(&member, name);
  756. spl_array_unset_dimension(object, &member);
  757. return;
  758. }
  759. zend_std_unset_property(object, name, cache_slot);
  760. } /* }}} */
  761. static int spl_array_compare_objects(zval *o1, zval *o2) /* {{{ */
  762. {
  763. HashTable *ht1,
  764. *ht2;
  765. spl_array_object *intern1,
  766. *intern2;
  767. int result = 0;
  768. ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2);
  769. intern1 = Z_SPLARRAY_P(o1);
  770. intern2 = Z_SPLARRAY_P(o2);
  771. ht1 = spl_array_get_hash_table(intern1);
  772. ht2 = spl_array_get_hash_table(intern2);
  773. result = zend_compare_symbol_tables(ht1, ht2);
  774. /* if we just compared std.properties, don't do it again */
  775. if (result == 0 &&
  776. !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
  777. result = zend_std_compare_objects(o1, o2);
  778. }
  779. return result;
  780. } /* }}} */
  781. static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht) /* {{{ */
  782. {
  783. zend_string *string_key;
  784. zend_ulong num_key;
  785. zval *data;
  786. if (spl_array_is_object(intern)) {
  787. uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
  788. do {
  789. if (zend_hash_get_current_key_ex(aht, &string_key, &num_key, pos_ptr) == HASH_KEY_IS_STRING) {
  790. data = zend_hash_get_current_data_ex(aht, pos_ptr);
  791. if (data && Z_TYPE_P(data) == IS_INDIRECT &&
  792. Z_TYPE_P(data = Z_INDIRECT_P(data)) == IS_UNDEF) {
  793. /* skip */
  794. } else if (!ZSTR_LEN(string_key) || ZSTR_VAL(string_key)[0]) {
  795. return SUCCESS;
  796. }
  797. } else {
  798. return SUCCESS;
  799. }
  800. if (zend_hash_has_more_elements_ex(aht, pos_ptr) != SUCCESS) {
  801. return FAILURE;
  802. }
  803. zend_hash_move_forward_ex(aht, pos_ptr);
  804. } while (1);
  805. }
  806. return FAILURE;
  807. } /* }}} */
  808. static int spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */
  809. {
  810. uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
  811. zend_hash_move_forward_ex(aht, pos_ptr);
  812. if (spl_array_is_object(intern)) {
  813. return spl_array_skip_protected(intern, aht);
  814. } else {
  815. return zend_hash_has_more_elements_ex(aht, pos_ptr);
  816. }
  817. } /* }}} */
  818. static int spl_array_next(spl_array_object *intern) /* {{{ */
  819. {
  820. HashTable *aht = spl_array_get_hash_table(intern);
  821. return spl_array_next_ex(intern, aht);
  822. } /* }}} */
  823. static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */
  824. {
  825. zend_user_it_invalidate_current(iter);
  826. zval_ptr_dtor(&iter->data);
  827. }
  828. /* }}} */
  829. static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
  830. {
  831. spl_array_object *object = Z_SPLARRAY_P(&iter->data);
  832. HashTable *aht = spl_array_get_hash_table(object);
  833. if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
  834. return zend_user_it_valid(iter);
  835. } else {
  836. return zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, object));
  837. }
  838. }
  839. /* }}} */
  840. static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
  841. {
  842. spl_array_object *object = Z_SPLARRAY_P(&iter->data);
  843. HashTable *aht = spl_array_get_hash_table(object);
  844. if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
  845. return zend_user_it_get_current_data(iter);
  846. } else {
  847. zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object));
  848. if (data && Z_TYPE_P(data) == IS_INDIRECT) {
  849. data = Z_INDIRECT_P(data);
  850. }
  851. return data;
  852. }
  853. }
  854. /* }}} */
  855. static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
  856. {
  857. spl_array_object *object = Z_SPLARRAY_P(&iter->data);
  858. HashTable *aht = spl_array_get_hash_table(object);
  859. if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
  860. zend_user_it_get_current_key(iter, key);
  861. } else {
  862. zend_hash_get_current_key_zval_ex(aht, key, spl_array_get_pos_ptr(aht, object));
  863. }
  864. }
  865. /* }}} */
  866. static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
  867. {
  868. spl_array_object *object = Z_SPLARRAY_P(&iter->data);
  869. HashTable *aht = spl_array_get_hash_table(object);
  870. if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
  871. zend_user_it_move_forward(iter);
  872. } else {
  873. zend_user_it_invalidate_current(iter);
  874. spl_array_next_ex(object, aht);
  875. }
  876. }
  877. /* }}} */
  878. static void spl_array_rewind(spl_array_object *intern) /* {{{ */
  879. {
  880. HashTable *aht = spl_array_get_hash_table(intern);
  881. if (intern->ht_iter == (uint32_t)-1) {
  882. spl_array_get_pos_ptr(aht, intern);
  883. } else {
  884. zend_hash_internal_pointer_reset_ex(aht, spl_array_get_pos_ptr(aht, intern));
  885. spl_array_skip_protected(intern, aht);
  886. }
  887. }
  888. /* }}} */
  889. static void spl_array_it_rewind(zend_object_iterator *iter) /* {{{ */
  890. {
  891. spl_array_object *object = Z_SPLARRAY_P(&iter->data);
  892. if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
  893. zend_user_it_rewind(iter);
  894. } else {
  895. zend_user_it_invalidate_current(iter);
  896. spl_array_rewind(object);
  897. }
  898. }
  899. /* }}} */
  900. static HashTable *spl_array_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
  901. {
  902. *n = 1;
  903. *table = &iter->data;
  904. return NULL;
  905. }
  906. /* {{{ spl_array_set_array */
  907. static void spl_array_set_array(zval *object, spl_array_object *intern, zval *array, zend_long ar_flags, int just_array) {
  908. if (Z_TYPE_P(array) != IS_OBJECT && Z_TYPE_P(array) != IS_ARRAY) {
  909. zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object", 0);
  910. return;
  911. }
  912. if (Z_TYPE_P(array) == IS_ARRAY) {
  913. zval_ptr_dtor(&intern->array);
  914. if (Z_REFCOUNT_P(array) == 1) {
  915. ZVAL_COPY(&intern->array, array);
  916. } else {
  917. //??? TODO: try to avoid array duplication
  918. ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array)));
  919. }
  920. } else {
  921. if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator) {
  922. zval_ptr_dtor(&intern->array);
  923. if (just_array) {
  924. spl_array_object *other = Z_SPLARRAY_P(array);
  925. ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
  926. }
  927. if (Z_OBJ_P(object) == Z_OBJ_P(array)) {
  928. ar_flags |= SPL_ARRAY_IS_SELF;
  929. ZVAL_UNDEF(&intern->array);
  930. } else {
  931. ar_flags |= SPL_ARRAY_USE_OTHER;
  932. ZVAL_COPY(&intern->array, array);
  933. }
  934. } else {
  935. zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties);
  936. if (handler != zend_std_get_properties) {
  937. zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
  938. "Overloaded object of type %s is not compatible with %s",
  939. ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name));
  940. return;
  941. }
  942. zval_ptr_dtor(&intern->array);
  943. ZVAL_COPY(&intern->array, array);
  944. }
  945. }
  946. intern->ar_flags &= ~SPL_ARRAY_IS_SELF & ~SPL_ARRAY_USE_OTHER;
  947. intern->ar_flags |= ar_flags;
  948. if (intern->ht_iter != (uint32_t)-1) {
  949. zend_hash_iterator_del(intern->ht_iter);
  950. intern->ht_iter = (uint32_t)-1;
  951. }
  952. }
  953. /* }}} */
  954. /* iterator handler table */
  955. static const zend_object_iterator_funcs spl_array_it_funcs = {
  956. spl_array_it_dtor,
  957. spl_array_it_valid,
  958. spl_array_it_get_current_data,
  959. spl_array_it_get_current_key,
  960. spl_array_it_move_forward,
  961. spl_array_it_rewind,
  962. NULL,
  963. spl_array_it_get_gc,
  964. };
  965. zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
  966. {
  967. zend_user_iterator *iterator;
  968. spl_array_object *array_object = Z_SPLARRAY_P(object);
  969. if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
  970. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  971. return NULL;
  972. }
  973. iterator = emalloc(sizeof(zend_user_iterator));
  974. zend_iterator_init(&iterator->it);
  975. ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
  976. iterator->it.funcs = &spl_array_it_funcs;
  977. iterator->ce = ce;
  978. ZVAL_UNDEF(&iterator->value);
  979. return &iterator->it;
  980. }
  981. /* }}} */
  982. /* {{{ Constructs a new array object from an array or object. */
  983. PHP_METHOD(ArrayObject, __construct)
  984. {
  985. zval *object = ZEND_THIS;
  986. spl_array_object *intern;
  987. zval *array;
  988. zend_long ar_flags = 0;
  989. zend_class_entry *ce_get_iterator = spl_ce_ArrayIterator;
  990. if (ZEND_NUM_ARGS() == 0) {
  991. return; /* nothing to do */
  992. }
  993. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|AlC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
  994. RETURN_THROWS();
  995. }
  996. intern = Z_SPLARRAY_P(object);
  997. if (ZEND_NUM_ARGS() > 2) {
  998. intern->ce_get_iterator = ce_get_iterator;
  999. }
  1000. ar_flags &= ~SPL_ARRAY_INT_MASK;
  1001. spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
  1002. }
  1003. /* }}} */
  1004. /* {{{ Constructs a new array iterator from an array or object. */
  1005. PHP_METHOD(ArrayIterator, __construct)
  1006. {
  1007. zval *object = ZEND_THIS;
  1008. spl_array_object *intern;
  1009. zval *array;
  1010. zend_long ar_flags = 0;
  1011. if (ZEND_NUM_ARGS() == 0) {
  1012. return; /* nothing to do */
  1013. }
  1014. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
  1015. RETURN_THROWS();
  1016. }
  1017. intern = Z_SPLARRAY_P(object);
  1018. ar_flags &= ~SPL_ARRAY_INT_MASK;
  1019. spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
  1020. }
  1021. /* }}} */
  1022. /* {{{ Set the class used in getIterator. */
  1023. PHP_METHOD(ArrayObject, setIteratorClass)
  1024. {
  1025. zval *object = ZEND_THIS;
  1026. spl_array_object *intern = Z_SPLARRAY_P(object);
  1027. zend_class_entry *ce_get_iterator = spl_ce_ArrayIterator;
  1028. ZEND_PARSE_PARAMETERS_START(1, 1)
  1029. Z_PARAM_CLASS(ce_get_iterator)
  1030. ZEND_PARSE_PARAMETERS_END();
  1031. intern->ce_get_iterator = ce_get_iterator;
  1032. }
  1033. /* }}} */
  1034. /* {{{ Get the class used in getIterator. */
  1035. PHP_METHOD(ArrayObject, getIteratorClass)
  1036. {
  1037. zval *object = ZEND_THIS;
  1038. spl_array_object *intern = Z_SPLARRAY_P(object);
  1039. if (zend_parse_parameters_none() == FAILURE) {
  1040. RETURN_THROWS();
  1041. }
  1042. zend_string_addref(intern->ce_get_iterator->name);
  1043. RETURN_STR(intern->ce_get_iterator->name);
  1044. }
  1045. /* }}} */
  1046. /* {{{ Get flags */
  1047. PHP_METHOD(ArrayObject, getFlags)
  1048. {
  1049. zval *object = ZEND_THIS;
  1050. spl_array_object *intern = Z_SPLARRAY_P(object);
  1051. if (zend_parse_parameters_none() == FAILURE) {
  1052. RETURN_THROWS();
  1053. }
  1054. RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
  1055. }
  1056. /* }}} */
  1057. /* {{{ Set flags */
  1058. PHP_METHOD(ArrayObject, setFlags)
  1059. {
  1060. zval *object = ZEND_THIS;
  1061. spl_array_object *intern = Z_SPLARRAY_P(object);
  1062. zend_long ar_flags = 0;
  1063. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ar_flags) == FAILURE) {
  1064. RETURN_THROWS();
  1065. }
  1066. intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
  1067. }
  1068. /* }}} */
  1069. /* {{{ Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
  1070. PHP_METHOD(ArrayObject, exchangeArray)
  1071. {
  1072. zval *object = ZEND_THIS, *array;
  1073. spl_array_object *intern = Z_SPLARRAY_P(object);
  1074. if (zend_parse_parameters(ZEND_NUM_ARGS(), "A", &array) == FAILURE) {
  1075. RETURN_THROWS();
  1076. }
  1077. if (intern->nApplyCount > 0) {
  1078. zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
  1079. RETURN_THROWS();
  1080. }
  1081. RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
  1082. spl_array_set_array(object, intern, array, 0L, 1);
  1083. }
  1084. /* }}} */
  1085. /* {{{ Create a new iterator from a ArrayObject instance */
  1086. PHP_METHOD(ArrayObject, getIterator)
  1087. {
  1088. zval *object = ZEND_THIS;
  1089. spl_array_object *intern = Z_SPLARRAY_P(object);
  1090. if (zend_parse_parameters_none() == FAILURE) {
  1091. RETURN_THROWS();
  1092. }
  1093. RETURN_OBJ(spl_array_object_new_ex(intern->ce_get_iterator, Z_OBJ_P(object), 0));
  1094. }
  1095. /* }}} */
  1096. /* {{{ Rewind array back to the start */
  1097. PHP_METHOD(ArrayIterator, rewind)
  1098. {
  1099. zval *object = ZEND_THIS;
  1100. spl_array_object *intern = Z_SPLARRAY_P(object);
  1101. if (zend_parse_parameters_none() == FAILURE) {
  1102. RETURN_THROWS();
  1103. }
  1104. spl_array_rewind(intern);
  1105. }
  1106. /* }}} */
  1107. /* {{{ Seek to position. */
  1108. PHP_METHOD(ArrayIterator, seek)
  1109. {
  1110. zend_long opos, position;
  1111. zval *object = ZEND_THIS;
  1112. spl_array_object *intern = Z_SPLARRAY_P(object);
  1113. HashTable *aht = spl_array_get_hash_table(intern);
  1114. int result;
  1115. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
  1116. RETURN_THROWS();
  1117. }
  1118. opos = position;
  1119. if (position >= 0) { /* negative values are not supported */
  1120. spl_array_rewind(intern);
  1121. result = SUCCESS;
  1122. while (position-- > 0 && (result = spl_array_next(intern)) == SUCCESS);
  1123. if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS) {
  1124. return; /* ok */
  1125. }
  1126. }
  1127. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", opos);
  1128. } /* }}} */
  1129. static zend_long spl_array_object_count_elements_helper(spl_array_object *intern) /* {{{ */
  1130. {
  1131. HashTable *aht = spl_array_get_hash_table(intern);
  1132. if (spl_array_is_object(intern)) {
  1133. zend_long count = 0;
  1134. zend_string *key;
  1135. zval *val;
  1136. /* Count public/dynamic properties */
  1137. ZEND_HASH_FOREACH_STR_KEY_VAL(aht, key, val) {
  1138. if (Z_TYPE_P(val) == IS_INDIRECT) {
  1139. if (Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF) continue;
  1140. if (key && ZSTR_VAL(key)[0] == '\0') continue;
  1141. }
  1142. count++;
  1143. } ZEND_HASH_FOREACH_END();
  1144. return count;
  1145. } else {
  1146. return zend_hash_num_elements(aht);
  1147. }
  1148. } /* }}} */
  1149. int spl_array_object_count_elements(zend_object *object, zend_long *count) /* {{{ */
  1150. {
  1151. spl_array_object *intern = spl_array_from_obj(object);
  1152. if (intern->fptr_count) {
  1153. zval rv;
  1154. zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
  1155. if (Z_TYPE(rv) != IS_UNDEF) {
  1156. *count = zval_get_long(&rv);
  1157. zval_ptr_dtor(&rv);
  1158. return SUCCESS;
  1159. }
  1160. *count = 0;
  1161. return FAILURE;
  1162. }
  1163. *count = spl_array_object_count_elements_helper(intern);
  1164. return SUCCESS;
  1165. } /* }}} */
  1166. /* {{{ Return the number of elements in the Iterator. */
  1167. PHP_METHOD(ArrayObject, count)
  1168. {
  1169. spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
  1170. if (zend_parse_parameters_none() == FAILURE) {
  1171. RETURN_THROWS();
  1172. }
  1173. RETURN_LONG(spl_array_object_count_elements_helper(intern));
  1174. } /* }}} */
  1175. static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
  1176. {
  1177. spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
  1178. HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern);
  1179. HashTable *aht = *ht_ptr;
  1180. zval function_name, params[2], *arg = NULL;
  1181. ZVAL_STRINGL(&function_name, fname, fname_len);
  1182. ZVAL_NEW_EMPTY_REF(&params[0]);
  1183. ZVAL_ARR(Z_REFVAL(params[0]), aht);
  1184. GC_ADDREF(aht);
  1185. if (!use_arg) {
  1186. if (zend_parse_parameters_none() == FAILURE) {
  1187. goto exit;
  1188. }
  1189. intern->nApplyCount++;
  1190. call_user_function(EG(function_table), NULL, &function_name, return_value, 1, params);
  1191. intern->nApplyCount--;
  1192. } else if (use_arg == SPL_ARRAY_METHOD_SORT_FLAGS_ARG) {
  1193. zend_long sort_flags = 0;
  1194. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) {
  1195. goto exit;
  1196. }
  1197. ZVAL_LONG(&params[1], sort_flags);
  1198. intern->nApplyCount++;
  1199. call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params);
  1200. intern->nApplyCount--;
  1201. } else {
  1202. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
  1203. goto exit;
  1204. }
  1205. ZVAL_COPY_VALUE(&params[1], arg);
  1206. intern->nApplyCount++;
  1207. call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params);
  1208. intern->nApplyCount--;
  1209. }
  1210. exit:
  1211. {
  1212. zval *ht_zv = Z_REFVAL(params[0]);
  1213. zend_array_release(*ht_ptr);
  1214. SEPARATE_ARRAY(ht_zv);
  1215. *ht_ptr = Z_ARRVAL_P(ht_zv);
  1216. ZVAL_NULL(ht_zv);
  1217. zval_ptr_dtor(&params[0]);
  1218. zend_string_free(Z_STR(function_name));
  1219. }
  1220. } /* }}} */
  1221. #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
  1222. PHP_METHOD(cname, fname) \
  1223. { \
  1224. spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
  1225. }
  1226. /* {{{ Sort the entries by values. */
  1227. SPL_ARRAY_METHOD(ArrayObject, asort, SPL_ARRAY_METHOD_SORT_FLAGS_ARG) /* }}} */
  1228. /* {{{ Sort the entries by key. */
  1229. SPL_ARRAY_METHOD(ArrayObject, ksort, SPL_ARRAY_METHOD_SORT_FLAGS_ARG) /* }}} */
  1230. /* {{{ Sort the entries by values user defined function. */
  1231. SPL_ARRAY_METHOD(ArrayObject, uasort, SPL_ARRAY_METHOD_CALLBACK_ARG) /* }}} */
  1232. /* {{{ Sort the entries by key using user defined function. */
  1233. SPL_ARRAY_METHOD(ArrayObject, uksort, SPL_ARRAY_METHOD_CALLBACK_ARG) /* }}} */
  1234. /* {{{ Sort the entries by values using "natural order" algorithm. */
  1235. SPL_ARRAY_METHOD(ArrayObject, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
  1236. /* {{{ Sort the entries by key using case insensitive "natural order" algorithm. */
  1237. SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
  1238. /* {{{ Return current array entry */
  1239. PHP_METHOD(ArrayIterator, current)
  1240. {
  1241. zval *object = ZEND_THIS;
  1242. spl_array_object *intern = Z_SPLARRAY_P(object);
  1243. zval *entry;
  1244. HashTable *aht = spl_array_get_hash_table(intern);
  1245. if (zend_parse_parameters_none() == FAILURE) {
  1246. RETURN_THROWS();
  1247. }
  1248. if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
  1249. return;
  1250. }
  1251. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  1252. entry = Z_INDIRECT_P(entry);
  1253. if (Z_TYPE_P(entry) == IS_UNDEF) {
  1254. return;
  1255. }
  1256. }
  1257. RETURN_COPY_DEREF(entry);
  1258. }
  1259. /* }}} */
  1260. /* {{{ Return current array key */
  1261. PHP_METHOD(ArrayIterator, key)
  1262. {
  1263. if (zend_parse_parameters_none() == FAILURE) {
  1264. RETURN_THROWS();
  1265. }
  1266. spl_array_iterator_key(ZEND_THIS, return_value);
  1267. } /* }}} */
  1268. void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */
  1269. {
  1270. spl_array_object *intern = Z_SPLARRAY_P(object);
  1271. HashTable *aht = spl_array_get_hash_table(intern);
  1272. zend_hash_get_current_key_zval_ex(aht, return_value, spl_array_get_pos_ptr(aht, intern));
  1273. }
  1274. /* }}} */
  1275. /* {{{ Move to next entry */
  1276. PHP_METHOD(ArrayIterator, next)
  1277. {
  1278. zval *object = ZEND_THIS;
  1279. spl_array_object *intern = Z_SPLARRAY_P(object);
  1280. HashTable *aht = spl_array_get_hash_table(intern);
  1281. if (zend_parse_parameters_none() == FAILURE) {
  1282. RETURN_THROWS();
  1283. }
  1284. spl_array_next_ex(intern, aht);
  1285. }
  1286. /* }}} */
  1287. /* {{{ Check whether array contains more entries */
  1288. PHP_METHOD(ArrayIterator, valid)
  1289. {
  1290. zval *object = ZEND_THIS;
  1291. spl_array_object *intern = Z_SPLARRAY_P(object);
  1292. HashTable *aht = spl_array_get_hash_table(intern);
  1293. if (zend_parse_parameters_none() == FAILURE) {
  1294. RETURN_THROWS();
  1295. }
  1296. RETURN_BOOL(zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS);
  1297. }
  1298. /* }}} */
  1299. /* {{{ Check whether current element has children (e.g. is an array) */
  1300. PHP_METHOD(RecursiveArrayIterator, hasChildren)
  1301. {
  1302. zval *object = ZEND_THIS, *entry;
  1303. spl_array_object *intern = Z_SPLARRAY_P(object);
  1304. HashTable *aht = spl_array_get_hash_table(intern);
  1305. if (zend_parse_parameters_none() == FAILURE) {
  1306. RETURN_THROWS();
  1307. }
  1308. if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
  1309. RETURN_FALSE;
  1310. }
  1311. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  1312. entry = Z_INDIRECT_P(entry);
  1313. }
  1314. ZVAL_DEREF(entry);
  1315. RETURN_BOOL(Z_TYPE_P(entry) == IS_ARRAY || (Z_TYPE_P(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
  1316. }
  1317. /* }}} */
  1318. /* {{{ Create a sub iterator for the current element (same class as $this) */
  1319. PHP_METHOD(RecursiveArrayIterator, getChildren)
  1320. {
  1321. zval *object = ZEND_THIS, *entry, flags;
  1322. spl_array_object *intern = Z_SPLARRAY_P(object);
  1323. HashTable *aht = spl_array_get_hash_table(intern);
  1324. if (zend_parse_parameters_none() == FAILURE) {
  1325. RETURN_THROWS();
  1326. }
  1327. if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
  1328. return;
  1329. }
  1330. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  1331. entry = Z_INDIRECT_P(entry);
  1332. }
  1333. ZVAL_DEREF(entry);
  1334. if (Z_TYPE_P(entry) == IS_OBJECT) {
  1335. if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
  1336. return;
  1337. }
  1338. if (instanceof_function(Z_OBJCE_P(entry), Z_OBJCE_P(ZEND_THIS))) {
  1339. RETURN_OBJ_COPY(Z_OBJ_P(entry));
  1340. }
  1341. }
  1342. ZVAL_LONG(&flags, intern->ar_flags);
  1343. spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags);
  1344. }
  1345. /* }}} */
  1346. /* {{{ Serialize the object */
  1347. PHP_METHOD(ArrayObject, serialize)
  1348. {
  1349. zval *object = ZEND_THIS;
  1350. spl_array_object *intern = Z_SPLARRAY_P(object);
  1351. zval members, flags;
  1352. php_serialize_data_t var_hash;
  1353. smart_str buf = {0};
  1354. if (zend_parse_parameters_none() == FAILURE) {
  1355. RETURN_THROWS();
  1356. }
  1357. PHP_VAR_SERIALIZE_INIT(var_hash);
  1358. ZVAL_LONG(&flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
  1359. /* storage */
  1360. smart_str_appendl(&buf, "x:", 2);
  1361. php_var_serialize(&buf, &flags, &var_hash);
  1362. if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
  1363. php_var_serialize(&buf, &intern->array, &var_hash);
  1364. smart_str_appendc(&buf, ';');
  1365. }
  1366. /* members */
  1367. smart_str_appendl(&buf, "m:", 2);
  1368. if (!intern->std.properties) {
  1369. rebuild_object_properties(&intern->std);
  1370. }
  1371. ZVAL_ARR(&members, intern->std.properties);
  1372. php_var_serialize(&buf, &members, &var_hash); /* finishes the string */
  1373. /* done */
  1374. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  1375. RETURN_NEW_STR(buf.s);
  1376. } /* }}} */
  1377. /* {{{ unserialize the object */
  1378. PHP_METHOD(ArrayObject, unserialize)
  1379. {
  1380. zval *object = ZEND_THIS;
  1381. spl_array_object *intern = Z_SPLARRAY_P(object);
  1382. char *buf;
  1383. size_t buf_len;
  1384. const unsigned char *p, *s;
  1385. php_unserialize_data_t var_hash;
  1386. zval *members, *zflags, *array;
  1387. zend_long flags;
  1388. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
  1389. RETURN_THROWS();
  1390. }
  1391. if (buf_len == 0) {
  1392. return;
  1393. }
  1394. if (intern->nApplyCount > 0) {
  1395. zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
  1396. return;
  1397. }
  1398. /* storage */
  1399. s = p = (const unsigned char*)buf;
  1400. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  1401. if (*p!= 'x' || *++p != ':') {
  1402. goto outexcept;
  1403. }
  1404. ++p;
  1405. zflags = var_tmp_var(&var_hash);
  1406. if (!php_var_unserialize(zflags, &p, s + buf_len, &var_hash) || Z_TYPE_P(zflags) != IS_LONG) {
  1407. goto outexcept;
  1408. }
  1409. --p; /* for ';' */
  1410. flags = Z_LVAL_P(zflags);
  1411. /* flags needs to be verified and we also need to verify whether the next
  1412. * thing we get is ';'. After that we require an 'm' or something else
  1413. * where 'm' stands for members and anything else should be an array. If
  1414. * neither 'a' or 'm' follows we have an error. */
  1415. if (*p != ';') {
  1416. goto outexcept;
  1417. }
  1418. ++p;
  1419. if (flags & SPL_ARRAY_IS_SELF) {
  1420. /* If IS_SELF is used, the flags are not followed by an array/object */
  1421. intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
  1422. intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
  1423. zval_ptr_dtor(&intern->array);
  1424. ZVAL_UNDEF(&intern->array);
  1425. } else {
  1426. if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
  1427. goto outexcept;
  1428. }
  1429. array = var_tmp_var(&var_hash);
  1430. if (!php_var_unserialize(array, &p, s + buf_len, &var_hash)
  1431. || (Z_TYPE_P(array) != IS_ARRAY && Z_TYPE_P(array) != IS_OBJECT)) {
  1432. goto outexcept;
  1433. }
  1434. intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
  1435. intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
  1436. if (Z_TYPE_P(array) == IS_ARRAY) {
  1437. zval_ptr_dtor(&intern->array);
  1438. ZVAL_COPY_VALUE(&intern->array, array);
  1439. ZVAL_NULL(array);
  1440. SEPARATE_ARRAY(&intern->array);
  1441. } else {
  1442. spl_array_set_array(object, intern, array, 0L, 1);
  1443. }
  1444. if (*p != ';') {
  1445. goto outexcept;
  1446. }
  1447. ++p;
  1448. }
  1449. /* members */
  1450. if (*p!= 'm' || *++p != ':') {
  1451. goto outexcept;
  1452. }
  1453. ++p;
  1454. members = var_tmp_var(&var_hash);
  1455. if (!php_var_unserialize(members, &p, s + buf_len, &var_hash) || Z_TYPE_P(members) != IS_ARRAY) {
  1456. goto outexcept;
  1457. }
  1458. /* copy members */
  1459. object_properties_load(&intern->std, Z_ARRVAL_P(members));
  1460. /* done reading $serialized */
  1461. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  1462. return;
  1463. outexcept:
  1464. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  1465. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset " ZEND_LONG_FMT " of %zd bytes", (zend_long)((char*)p - buf), buf_len);
  1466. RETURN_THROWS();
  1467. } /* }}} */
  1468. /* {{{ */
  1469. PHP_METHOD(ArrayObject, __serialize)
  1470. {
  1471. spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
  1472. zval tmp;
  1473. if (zend_parse_parameters_none() == FAILURE) {
  1474. RETURN_THROWS();
  1475. }
  1476. array_init(return_value);
  1477. /* flags */
  1478. ZVAL_LONG(&tmp, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
  1479. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  1480. /* storage */
  1481. if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
  1482. ZVAL_NULL(&tmp);
  1483. } else {
  1484. ZVAL_COPY(&tmp, &intern->array);
  1485. }
  1486. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  1487. /* members */
  1488. ZVAL_ARR(&tmp, zend_proptable_to_symtable(
  1489. zend_std_get_properties(&intern->std), /* always_duplicate */ 1));
  1490. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  1491. /* iterator class */
  1492. if (intern->ce_get_iterator == spl_ce_ArrayIterator) {
  1493. ZVAL_NULL(&tmp);
  1494. } else {
  1495. ZVAL_STR_COPY(&tmp, intern->ce_get_iterator->name);
  1496. }
  1497. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  1498. }
  1499. /* }}} */
  1500. /* {{{ */
  1501. PHP_METHOD(ArrayObject, __unserialize)
  1502. {
  1503. spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
  1504. HashTable *data;
  1505. zval *flags_zv, *storage_zv, *members_zv, *iterator_class_zv;
  1506. zend_long flags;
  1507. if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
  1508. RETURN_THROWS();
  1509. }
  1510. flags_zv = zend_hash_index_find(data, 0);
  1511. storage_zv = zend_hash_index_find(data, 1);
  1512. members_zv = zend_hash_index_find(data, 2);
  1513. iterator_class_zv = zend_hash_index_find(data, 3);
  1514. if (!flags_zv || !storage_zv || !members_zv ||
  1515. Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY ||
  1516. (iterator_class_zv && (Z_TYPE_P(iterator_class_zv) != IS_NULL &&
  1517. Z_TYPE_P(iterator_class_zv) != IS_STRING))) {
  1518. zend_throw_exception(spl_ce_UnexpectedValueException,
  1519. "Incomplete or ill-typed serialization data", 0);
  1520. RETURN_THROWS();
  1521. }
  1522. flags = Z_LVAL_P(flags_zv);
  1523. intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
  1524. intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
  1525. if (flags & SPL_ARRAY_IS_SELF) {
  1526. zval_ptr_dtor(&intern->array);
  1527. ZVAL_UNDEF(&intern->array);
  1528. } else {
  1529. spl_array_set_array(ZEND_THIS, intern, storage_zv, 0L, 1);
  1530. }
  1531. object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
  1532. if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
  1533. zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
  1534. if (!ce) {
  1535. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
  1536. "Cannot deserialize ArrayObject with iterator class '%s'; no such class exists",
  1537. ZSTR_VAL(Z_STR_P(iterator_class_zv)));
  1538. RETURN_THROWS();
  1539. }
  1540. if (!instanceof_function(ce, zend_ce_iterator)) {
  1541. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
  1542. "Cannot deserialize ArrayObject with iterator class '%s'; this class does not implement the Iterator interface",
  1543. ZSTR_VAL(Z_STR_P(iterator_class_zv)));
  1544. RETURN_THROWS();
  1545. }
  1546. intern->ce_get_iterator = ce;
  1547. }
  1548. }
  1549. /* }}} */
  1550. /* {{{ */
  1551. PHP_METHOD(ArrayObject, __debugInfo)
  1552. {
  1553. if (zend_parse_parameters_none() == FAILURE) {
  1554. return;
  1555. }
  1556. RETURN_ARR(spl_array_get_debug_info(Z_OBJ_P(ZEND_THIS)));
  1557. } /* }}} */
  1558. /* {{{ PHP_MINIT_FUNCTION(spl_array) */
  1559. PHP_MINIT_FUNCTION(spl_array)
  1560. {
  1561. spl_ce_ArrayObject = register_class_ArrayObject(zend_ce_aggregate, zend_ce_arrayaccess, zend_ce_serializable, zend_ce_countable);
  1562. spl_ce_ArrayObject->create_object = spl_array_object_new;
  1563. memcpy(&spl_handler_ArrayObject, &std_object_handlers, sizeof(zend_object_handlers));
  1564. spl_handler_ArrayObject.offset = XtOffsetOf(spl_array_object, std);
  1565. spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
  1566. spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
  1567. spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
  1568. spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
  1569. spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
  1570. spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
  1571. spl_handler_ArrayObject.get_properties_for = spl_array_get_properties_for;
  1572. spl_handler_ArrayObject.get_gc = spl_array_get_gc;
  1573. spl_handler_ArrayObject.read_property = spl_array_read_property;
  1574. spl_handler_ArrayObject.write_property = spl_array_write_property;
  1575. spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
  1576. spl_handler_ArrayObject.has_property = spl_array_has_property;
  1577. spl_handler_ArrayObject.unset_property = spl_array_unset_property;
  1578. spl_handler_ArrayObject.compare = spl_array_compare_objects;
  1579. spl_handler_ArrayObject.free_obj = spl_array_object_free_storage;
  1580. spl_ce_ArrayIterator = register_class_ArrayIterator(spl_ce_SeekableIterator, zend_ce_arrayaccess, zend_ce_serializable, zend_ce_countable);
  1581. spl_ce_ArrayIterator->create_object = spl_array_object_new;
  1582. spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
  1583. spl_ce_ArrayIterator->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR;
  1584. memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
  1585. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1586. REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1587. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
  1588. REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
  1589. spl_ce_RecursiveArrayIterator = register_class_RecursiveArrayIterator(spl_ce_ArrayIterator, spl_ce_RecursiveIterator);
  1590. spl_ce_RecursiveArrayIterator->create_object = spl_array_object_new;
  1591. spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
  1592. spl_ce_RecursiveArrayIterator->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR;
  1593. REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
  1594. return SUCCESS;
  1595. }
  1596. /* }}} */