/src/php-src/ext/spl/spl_fixedarray.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Copyright © The PHP Group and Contributors. | |
4 | | +----------------------------------------------------------------------+ |
5 | | | This source file is subject to the Modified BSD License that is | |
6 | | | bundled with this package in the file LICENSE, and is available | |
7 | | | through the World Wide Web at <https://www.php.net/license/>. | |
8 | | | | |
9 | | | SPDX-License-Identifier: BSD-3-Clause | |
10 | | +----------------------------------------------------------------------+ |
11 | | | Author: Antony Dovgal <tony@daylessday.org> | |
12 | | | Etienne Kneuss <colder@php.net> | |
13 | | +----------------------------------------------------------------------+ |
14 | | */ |
15 | | |
16 | | #ifdef HAVE_CONFIG_H |
17 | | #include <config.h> |
18 | | #endif |
19 | | |
20 | | #include "php.h" |
21 | | #include "zend_interfaces.h" |
22 | | #include "zend_exceptions.h" |
23 | | |
24 | | #include "spl_fixedarray_arginfo.h" |
25 | | #include "spl_fixedarray.h" |
26 | | #include "spl_exceptions.h" |
27 | | #include "ext/json/php_json.h" /* For php_json_serializable_ce */ |
28 | | |
29 | | static zend_object_handlers spl_handler_SplFixedArray; |
30 | | PHPAPI zend_class_entry *spl_ce_SplFixedArray; |
31 | | |
32 | | /* Check if the object is an instance of a subclass of SplFixedArray that overrides method's implementation. |
33 | | * Expect subclassing SplFixedArray to be rare and check that first. */ |
34 | 0 | #define HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, method) UNEXPECTED((object)->ce != spl_ce_SplFixedArray && (object)->ce->arrayaccess_funcs_ptr->method->common.scope != spl_ce_SplFixedArray) |
35 | | |
36 | | typedef struct _spl_fixedarray { |
37 | | zend_long size; |
38 | | /* It is possible to resize this, so this can't be combined with the object */ |
39 | | zval *elements; |
40 | | /* If positive, it's a resize within a resize and the value gives the desired size. If -1, it's not. */ |
41 | | zend_long cached_resize; |
42 | | } spl_fixedarray; |
43 | | |
44 | | typedef struct _spl_fixedarray_object { |
45 | | spl_fixedarray array; |
46 | | zend_function *fptr_count; |
47 | | zend_object std; |
48 | | } spl_fixedarray_object; |
49 | | |
50 | | typedef struct _spl_fixedarray_it { |
51 | | zend_object_iterator intern; |
52 | | zend_long current; |
53 | | } spl_fixedarray_it; |
54 | | |
55 | 20.8k | #define spl_fixed_array_from_obj(obj) ZEND_CONTAINER_OF(obj, spl_fixedarray_object, std) |
56 | | |
57 | 5.46k | #define Z_SPLFIXEDARRAY_P(zv) spl_fixed_array_from_obj(Z_OBJ_P((zv))) |
58 | | |
59 | | /* Helps enforce the invariants in debug mode: |
60 | | * - if size == 0, then elements == NULL |
61 | | * - if size > 0, then elements != NULL |
62 | | * - size is not less than 0 |
63 | | */ |
64 | | static bool spl_fixedarray_empty(spl_fixedarray *array) |
65 | 5.80k | { |
66 | 5.80k | if (array->elements) { |
67 | 2.15k | ZEND_ASSERT(array->size > 0); |
68 | 2.15k | return false; |
69 | 2.15k | } |
70 | 3.65k | ZEND_ASSERT(array->size == 0); |
71 | 3.65k | return true; |
72 | 3.65k | } |
73 | | |
74 | | /* True while spl_fixedarray_resize() runs. A clear empties the array before |
75 | | * destroying its elements, so emptiness alone cannot tell "never constructed" |
76 | | * from "clear in progress"; re-initialising in that window leaks. */ |
77 | | static bool spl_fixedarray_resize_in_progress(const spl_fixedarray *array) |
78 | 5.46k | { |
79 | 5.46k | return array->cached_resize >= 0; |
80 | 5.46k | } |
81 | | |
82 | | static void spl_fixedarray_default_ctor(spl_fixedarray *array) |
83 | 5.80k | { |
84 | 5.80k | array->size = 0; |
85 | 5.80k | array->elements = NULL; |
86 | 5.80k | array->cached_resize = -1; |
87 | 5.80k | } |
88 | | |
89 | | /* Initializes the range [from, to) to null. Does not dtor existing elements. */ |
90 | | static void spl_fixedarray_init_elems(spl_fixedarray *array, zend_long from, zend_long to) |
91 | 1 | { |
92 | 1 | ZEND_ASSERT(from <= to); |
93 | 1 | zval *begin = array->elements + from, *end = array->elements + to; |
94 | | |
95 | 131k | while (begin != end) { |
96 | 131k | ZVAL_NULL(begin++); |
97 | 131k | } |
98 | 1 | } |
99 | | |
100 | | static zend_result spl_fixedarray_init_non_empty_struct(spl_fixedarray *array, zend_long size) |
101 | 5.46k | { |
102 | 5.46k | array->size = 0; /* reset size in case ecalloc() fails */ |
103 | 5.46k | array->cached_resize = -1; |
104 | 5.46k | if (size) { |
105 | 5.45k | array->elements = safe_femalloc(size, sizeof(zval), 0, /* fallible */ true); |
106 | 5.45k | if (UNEXPECTED(!array->elements)) { |
107 | 0 | return FAILURE; |
108 | 0 | } |
109 | 5.45k | array->size = size; |
110 | 5.45k | } else { |
111 | 4 | array->elements = NULL; |
112 | 4 | } |
113 | 5.46k | return SUCCESS; |
114 | 5.46k | } |
115 | | |
116 | | static zend_result spl_fixedarray_init(spl_fixedarray *array, zend_long size) |
117 | 5 | { |
118 | 5 | if (size > 0) { |
119 | 1 | if (UNEXPECTED(spl_fixedarray_init_non_empty_struct(array, size) == FAILURE)) { |
120 | 0 | return FAILURE; |
121 | 0 | } |
122 | 1 | spl_fixedarray_init_elems(array, 0, size); |
123 | 4 | } else { |
124 | 4 | spl_fixedarray_default_ctor(array); |
125 | 4 | } |
126 | 5 | return SUCCESS; |
127 | 5 | } |
128 | | |
129 | | /* Copies the range [begin, end) into the fixedarray, beginning at `offset`. |
130 | | * Does not dtor the existing elements. |
131 | | */ |
132 | | static void spl_fixedarray_copy_range(spl_fixedarray *array, zend_long offset, zval *begin, zval *end) |
133 | 0 | { |
134 | 0 | ZEND_ASSERT(offset >= 0); |
135 | 0 | ZEND_ASSERT(array->size - offset >= end - begin); |
136 | |
|
137 | 0 | zval *to = &array->elements[offset]; |
138 | 0 | while (begin != end) { |
139 | 0 | ZVAL_COPY(to++, begin++); |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | static zend_result spl_fixedarray_copy_ctor(spl_fixedarray *to, spl_fixedarray *from) |
144 | 0 | { |
145 | 0 | zend_long size = from->size; |
146 | 0 | if (UNEXPECTED(spl_fixedarray_init(to, size) == FAILURE)) { |
147 | 0 | return FAILURE; |
148 | 0 | } |
149 | 0 | if (size != 0) { |
150 | 0 | zval *begin = from->elements, *end = from->elements + size; |
151 | 0 | spl_fixedarray_copy_range(to, 0, begin, end); |
152 | 0 | } |
153 | 0 | return SUCCESS; |
154 | 0 | } |
155 | | |
156 | | /* Destructs the elements in the range [from, to). |
157 | | * Caller is expected to bounds check. |
158 | | */ |
159 | | static void spl_fixedarray_dtor_range(spl_fixedarray *array, zend_long from, zend_long to) |
160 | 0 | { |
161 | 0 | array->size = from; |
162 | 0 | zval *begin = array->elements + from, *end = array->elements + to; |
163 | 0 | while (begin != end) { |
164 | 0 | zval_ptr_dtor(begin++); |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | | /* Destructs and frees contents but not the array itself. |
169 | | * If you want to re-use the array then you need to re-initialize it. |
170 | | */ |
171 | | static void spl_fixedarray_dtor(spl_fixedarray *array) |
172 | 5.80k | { |
173 | 5.80k | if (!spl_fixedarray_empty(array)) { |
174 | 2.15k | zval *begin = array->elements, *end = array->elements + array->size; |
175 | 2.15k | array->elements = NULL; |
176 | 2.15k | array->size = 0; |
177 | 141k | while (begin != end) { |
178 | 139k | zval_ptr_dtor(--end); |
179 | 139k | } |
180 | 2.15k | efree(begin); |
181 | 2.15k | } |
182 | 5.80k | } |
183 | | |
184 | | static zend_result spl_fixedarray_resize(spl_fixedarray *array, zend_long size) |
185 | 0 | { |
186 | 0 | if (size == array->size) { |
187 | | /* nothing to do */ |
188 | 0 | return SUCCESS; |
189 | 0 | } |
190 | | |
191 | 0 | if (UNEXPECTED(array->cached_resize >= 0)) { |
192 | | /* We're already resizing, so just remember the desired size. |
193 | | * The resize will happen later. */ |
194 | 0 | array->cached_resize = size; |
195 | 0 | return SUCCESS; |
196 | 0 | } |
197 | | /* first initialization */ |
198 | 0 | if (array->size == 0) { |
199 | 0 | return spl_fixedarray_init(array, size); |
200 | 0 | } |
201 | | |
202 | 0 | array->cached_resize = size; |
203 | | |
204 | | /* clearing the array */ |
205 | 0 | if (size == 0) { |
206 | | /* Clears elements and size; resetting them afterwards would leak |
207 | | * anything a destructor re-installed. */ |
208 | 0 | spl_fixedarray_dtor(array); |
209 | 0 | } else if (size > array->size) { |
210 | 0 | zval *elements = safe_ferealloc(array->elements, size, sizeof(zval), 0, /* fallible */ true); |
211 | 0 | if (UNEXPECTED(!elements)) { |
212 | 0 | array->cached_resize = -1; |
213 | 0 | return FAILURE; |
214 | 0 | } |
215 | 0 | array->elements = elements; |
216 | 0 | spl_fixedarray_init_elems(array, array->size, size); |
217 | 0 | array->size = size; |
218 | 0 | } else { /* size < array->size */ |
219 | | /* Size set in spl_fixedarray_dtor_range() */ |
220 | 0 | spl_fixedarray_dtor_range(array, size, array->size); |
221 | 0 | array->elements = erealloc(array->elements, sizeof(zval) * size); |
222 | 0 | } |
223 | | |
224 | | /* If resized within the destructor, take the last resize command and |
225 | | * perform it. The sentinel is still set: re-initialising during a |
226 | | * resize is refused. */ |
227 | 0 | zend_long cached_resize = array->cached_resize; |
228 | 0 | ZEND_ASSERT(cached_resize >= 0); |
229 | |
|
230 | 0 | array->cached_resize = -1; |
231 | 0 | if (cached_resize != size) { |
232 | 0 | return spl_fixedarray_resize(array, cached_resize); |
233 | 0 | } |
234 | | |
235 | 0 | return SUCCESS; |
236 | 0 | } |
237 | | |
238 | | static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, int *n) |
239 | 9.55k | { |
240 | 9.55k | spl_fixedarray_object *intern = spl_fixed_array_from_obj(obj); |
241 | | |
242 | 9.55k | *table = intern->array.elements; |
243 | 9.55k | *n = (int)intern->array.size; |
244 | | |
245 | 9.55k | if (obj->properties == NULL && obj->ce->default_properties_count == 0) { |
246 | 6.45k | return NULL; |
247 | 6.45k | } else { |
248 | 3.09k | return zend_std_get_properties(obj); |
249 | 3.09k | } |
250 | 9.55k | } |
251 | | |
252 | | static HashTable* spl_fixedarray_object_get_properties_for(zend_object *obj, zend_prop_purpose purpose) |
253 | 0 | { |
254 | | /* This has __serialize, so the purpose is not ZEND_PROP_PURPOSE_SERIALIZE, which would expect a non-null return value */ |
255 | 0 | ZEND_ASSERT(purpose != ZEND_PROP_PURPOSE_SERIALIZE); |
256 | |
|
257 | 0 | const spl_fixedarray_object *intern = spl_fixed_array_from_obj(obj); |
258 | | /* |
259 | | * SplFixedArray can be subclassed or have dynamic properties (With or without AllowDynamicProperties in subclasses). |
260 | | * Instances of subclasses with declared properties may have properties but not yet have a property table. |
261 | | */ |
262 | 0 | HashTable *source_properties = obj->properties ? obj->properties : (obj->ce->default_properties_count ? zend_std_get_properties(obj) : NULL); |
263 | |
|
264 | 0 | const zend_long size = intern->array.size; |
265 | 0 | if (size == 0 && (!source_properties || !zend_hash_num_elements(source_properties))) { |
266 | 0 | return NULL; |
267 | 0 | } |
268 | 0 | zval *const elements = intern->array.elements; |
269 | 0 | HashTable *ht = zend_new_array(size); |
270 | | |
271 | | /* The array elements are not *real properties*. */ |
272 | 0 | if (purpose != ZEND_PROP_PURPOSE_GET_OBJECT_VARS) { |
273 | 0 | for (zend_long i = 0; i < size; i++) { |
274 | 0 | Z_TRY_ADDREF_P(&elements[i]); |
275 | 0 | zend_hash_next_index_insert(ht, &elements[i]); |
276 | 0 | } |
277 | 0 | } |
278 | |
|
279 | 0 | if (source_properties && zend_hash_num_elements(source_properties) > 0) { |
280 | 0 | zend_long nkey; |
281 | 0 | zend_string *skey; |
282 | 0 | zval *value; |
283 | 0 | ZEND_HASH_MAP_FOREACH_KEY_VAL_IND(source_properties, nkey, skey, value) { |
284 | 0 | Z_TRY_ADDREF_P(value); |
285 | 0 | if (skey) { |
286 | 0 | zend_hash_add_new(ht, skey, value); |
287 | 0 | } else { |
288 | 0 | zend_hash_index_update(ht, nkey, value); |
289 | 0 | } |
290 | 0 | } ZEND_HASH_FOREACH_END(); |
291 | 0 | } |
292 | |
|
293 | 0 | return ht; |
294 | 0 | } |
295 | | |
296 | | static void spl_fixedarray_object_free_storage(zend_object *object) |
297 | 5.80k | { |
298 | 5.80k | spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); |
299 | 5.80k | spl_fixedarray_dtor(&intern->array); |
300 | 5.80k | zend_object_std_dtor(&intern->std); |
301 | 5.80k | } |
302 | | |
303 | | static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, zend_object *orig, bool clone_orig) |
304 | 5.80k | { |
305 | 5.80k | spl_fixedarray_object *intern; |
306 | 5.80k | zend_class_entry *parent = class_type; |
307 | | |
308 | 5.80k | intern = zend_object_alloc(sizeof(spl_fixedarray_object), parent); |
309 | | |
310 | 5.80k | zend_object_std_init(&intern->std, class_type); |
311 | 5.80k | object_properties_init(&intern->std, class_type); |
312 | | |
313 | 5.80k | if (orig && clone_orig) { |
314 | 0 | spl_fixedarray_object *other = spl_fixed_array_from_obj(orig); |
315 | 0 | if (UNEXPECTED(spl_fixedarray_copy_ctor(&intern->array, &other->array) == FAILURE)) { |
316 | 0 | ZEND_ASSERT(intern->std.handlers); |
317 | 0 | return &intern->std; |
318 | 0 | } |
319 | 5.80k | } else { |
320 | | /* The zeroed struct would mean "resizing"; set the sentinel. */ |
321 | 5.80k | spl_fixedarray_default_ctor(&intern->array); |
322 | 5.80k | } |
323 | | |
324 | 5.80k | if (UNEXPECTED(class_type != spl_ce_SplFixedArray)) { |
325 | | /* Find count() method */ |
326 | 0 | zend_function *fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT)); |
327 | 0 | if (fptr_count->common.scope == spl_ce_SplFixedArray) { |
328 | 0 | fptr_count = NULL; |
329 | 0 | } |
330 | 0 | intern->fptr_count = fptr_count; |
331 | 0 | } |
332 | | |
333 | 5.80k | return &intern->std; |
334 | 5.80k | } |
335 | | |
336 | | static zend_object *spl_fixedarray_new(zend_class_entry *class_type) |
337 | 5.80k | { |
338 | 5.80k | return spl_fixedarray_object_new_ex(class_type, NULL, false); |
339 | 5.80k | } |
340 | | |
341 | | static zend_object *spl_fixedarray_object_clone(zend_object *old_object) |
342 | 0 | { |
343 | 0 | zend_object *new_object = spl_fixedarray_object_new_ex(old_object->ce, old_object, true); |
344 | |
|
345 | 0 | zend_objects_clone_members(new_object, old_object); |
346 | |
|
347 | 0 | return new_object; |
348 | 0 | } |
349 | | |
350 | | static zend_never_inline zend_ulong spl_offset_convert_to_ulong_slow(const zval *offset) /* {{{ */ |
351 | 0 | { |
352 | 0 | try_again: |
353 | 0 | switch (Z_TYPE_P(offset)) { |
354 | 0 | case IS_STRING: { |
355 | 0 | zend_ulong index; |
356 | 0 | if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), index)) { |
357 | 0 | return index; |
358 | 0 | } |
359 | 0 | break; |
360 | 0 | } |
361 | 0 | case IS_DOUBLE: |
362 | 0 | return zend_dval_to_lval_safe(Z_DVAL_P(offset)); |
363 | 0 | case IS_LONG: |
364 | 0 | return Z_LVAL_P(offset); |
365 | 0 | case IS_FALSE: |
366 | 0 | return 0; |
367 | 0 | case IS_TRUE: |
368 | 0 | return 1; |
369 | 0 | case IS_REFERENCE: |
370 | 0 | offset = Z_REFVAL_P(offset); |
371 | 0 | goto try_again; |
372 | 0 | case IS_RESOURCE: |
373 | 0 | zend_use_resource_as_offset(offset); |
374 | 0 | return Z_RES_HANDLE_P(offset); |
375 | 0 | } |
376 | | |
377 | | /* Use SplFixedArray name from the CE */ |
378 | 0 | zend_illegal_container_offset(spl_ce_SplFixedArray->name, offset, BP_VAR_R); |
379 | 0 | return 0; |
380 | 0 | } |
381 | | |
382 | | /* Returned index is an unsigned number such that we don't have to do a negative check. |
383 | | * Negative numbers will be mapped at indices larger than ZEND_ULONG_MAX, |
384 | | * which is beyond the maximum length. */ |
385 | | static zend_always_inline zend_ulong spl_offset_convert_to_ulong(const zval *offset) |
386 | 0 | { |
387 | 0 | if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { |
388 | | /* Allow skipping exception check at call-site. */ |
389 | 0 | ZEND_ASSERT(!EG(exception)); |
390 | 0 | return Z_LVAL_P(offset); |
391 | 0 | } else { |
392 | 0 | return spl_offset_convert_to_ulong_slow(offset); |
393 | 0 | } |
394 | 0 | } |
395 | | |
396 | | static zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset) |
397 | 0 | { |
398 | | /* we have to return NULL on error here to avoid memleak because of |
399 | | * ZE duplicating uninitialized_zval_ptr */ |
400 | 0 | if (UNEXPECTED(!offset)) { |
401 | 0 | zend_throw_error(NULL, "[] operator not supported for SplFixedArray"); |
402 | 0 | return NULL; |
403 | 0 | } |
404 | | |
405 | 0 | zend_ulong index = spl_offset_convert_to_ulong(offset); |
406 | 0 | if (UNEXPECTED(EG(exception))) { |
407 | 0 | return NULL; |
408 | 0 | } |
409 | | |
410 | 0 | if (UNEXPECTED(index >= intern->array.size)) { |
411 | 0 | zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); |
412 | 0 | return NULL; |
413 | 0 | } else { |
414 | 0 | return &intern->array.elements[index]; |
415 | 0 | } |
416 | 0 | } |
417 | | |
418 | | static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset, int check_empty); |
419 | | |
420 | | static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *offset, int type, zval *rv) |
421 | 0 | { |
422 | 0 | if (type == BP_VAR_IS && !spl_fixedarray_object_has_dimension(object, offset, 0)) { |
423 | 0 | return &EG(uninitialized_zval); |
424 | 0 | } |
425 | | |
426 | 0 | if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetget)) { |
427 | 0 | zval tmp; |
428 | 0 | if (!offset) { |
429 | 0 | ZVAL_NULL(&tmp); |
430 | 0 | offset = &tmp; |
431 | 0 | } |
432 | 0 | zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetget, object, rv, offset); |
433 | 0 | if (!Z_ISUNDEF_P(rv)) { |
434 | 0 | return rv; |
435 | 0 | } |
436 | 0 | return &EG(uninitialized_zval); |
437 | 0 | } |
438 | | |
439 | 0 | spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); |
440 | 0 | return spl_fixedarray_object_read_dimension_helper(intern, offset); |
441 | 0 | } |
442 | | |
443 | | static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value) |
444 | 0 | { |
445 | 0 | if (UNEXPECTED(!offset)) { |
446 | | /* '$array[] = value' syntax is not supported */ |
447 | 0 | zend_throw_error(NULL, "[] operator not supported for SplFixedArray"); |
448 | 0 | return; |
449 | 0 | } |
450 | | |
451 | 0 | zend_ulong index = spl_offset_convert_to_ulong(offset); |
452 | 0 | if (UNEXPECTED(EG(exception))) { |
453 | 0 | return; |
454 | 0 | } |
455 | | |
456 | 0 | if (UNEXPECTED(index >= intern->array.size)) { |
457 | 0 | zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); |
458 | 0 | } else { |
459 | | /* Fix #81429 */ |
460 | 0 | zval *ptr = &(intern->array.elements[index]); |
461 | | /* This should be guaranteed by the VM handler or argument parsing. */ |
462 | 0 | ZEND_ASSERT(Z_TYPE_P(value) != IS_REFERENCE); |
463 | 0 | Z_TRY_ADDREF_P(value); |
464 | 0 | zend_safe_assign_to_variable_noref(ptr, value); |
465 | 0 | } |
466 | 0 | } |
467 | | |
468 | | static void spl_fixedarray_object_write_dimension(zend_object *object, zval *offset, zval *value) |
469 | 0 | { |
470 | 0 | if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetset)) { |
471 | 0 | zval tmp; |
472 | |
|
473 | 0 | if (!offset) { |
474 | 0 | ZVAL_NULL(&tmp); |
475 | 0 | offset = &tmp; |
476 | 0 | } |
477 | 0 | zend_call_known_instance_method_with_2_params(object->ce->arrayaccess_funcs_ptr->zf_offsetset, object, NULL, offset, value); |
478 | 0 | return; |
479 | 0 | } |
480 | | |
481 | 0 | spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); |
482 | 0 | spl_fixedarray_object_write_dimension_helper(intern, offset, value); |
483 | 0 | } |
484 | | |
485 | | static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset) |
486 | 0 | { |
487 | 0 | zend_ulong index = spl_offset_convert_to_ulong(offset); |
488 | 0 | if (UNEXPECTED(EG(exception))) { |
489 | 0 | return; |
490 | 0 | } |
491 | | |
492 | 0 | if (UNEXPECTED(index >= intern->array.size)) { |
493 | 0 | zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0); |
494 | 0 | } else { |
495 | 0 | zval null = {0}; |
496 | 0 | ZVAL_NULL(&null); |
497 | 0 | zend_safe_assign_to_variable_noref(&intern->array.elements[index], &null); |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | | static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *offset) |
502 | 0 | { |
503 | 0 | if (UNEXPECTED(HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetunset))) { |
504 | 0 | zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetunset, object, NULL, offset); |
505 | 0 | return; |
506 | 0 | } |
507 | | |
508 | 0 | spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); |
509 | 0 | spl_fixedarray_object_unset_dimension_helper(intern, offset); |
510 | 0 | } |
511 | | |
512 | | static bool spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, bool check_empty) |
513 | 0 | { |
514 | 0 | zend_ulong index = spl_offset_convert_to_ulong(offset); |
515 | 0 | if (UNEXPECTED(EG(exception))) { |
516 | 0 | return false; |
517 | 0 | } |
518 | | |
519 | 0 | if (index >= intern->array.size) { |
520 | 0 | return false; |
521 | 0 | } |
522 | | |
523 | 0 | if (check_empty) { |
524 | 0 | return zend_is_true(&intern->array.elements[index]); |
525 | 0 | } |
526 | | |
527 | 0 | return Z_TYPE(intern->array.elements[index]) != IS_NULL; |
528 | 0 | } |
529 | | |
530 | | static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset, int check_empty) |
531 | 0 | { |
532 | 0 | if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetexists)) { |
533 | 0 | zval rv; |
534 | |
|
535 | 0 | zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetexists, object, &rv, offset); |
536 | 0 | bool result = zend_is_true(&rv); |
537 | 0 | zval_ptr_dtor(&rv); |
538 | 0 | return result; |
539 | 0 | } |
540 | | |
541 | 0 | spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); |
542 | |
|
543 | 0 | return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty); |
544 | 0 | } |
545 | | |
546 | | static zend_result spl_fixedarray_object_count_elements(zend_object *object, zend_long *count) |
547 | 0 | { |
548 | 0 | spl_fixedarray_object *intern; |
549 | |
|
550 | 0 | intern = spl_fixed_array_from_obj(object); |
551 | 0 | if (UNEXPECTED(intern->fptr_count)) { |
552 | 0 | zval rv; |
553 | 0 | zend_call_known_instance_method_with_0_params(intern->fptr_count, object, &rv); |
554 | 0 | if (!Z_ISUNDEF(rv)) { |
555 | 0 | *count = zval_get_long(&rv); |
556 | 0 | zval_ptr_dtor(&rv); |
557 | 0 | } else { |
558 | 0 | *count = 0; |
559 | 0 | } |
560 | 0 | } else { |
561 | 0 | *count = intern->array.size; |
562 | 0 | } |
563 | 0 | return SUCCESS; |
564 | 0 | } |
565 | | |
566 | | PHP_METHOD(SplFixedArray, __construct) |
567 | 4 | { |
568 | 4 | zval *object = ZEND_THIS; |
569 | 4 | spl_fixedarray_object *intern; |
570 | 4 | zend_long size = 0; |
571 | | |
572 | 4 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &size) == FAILURE) { |
573 | 0 | RETURN_THROWS(); |
574 | 0 | } |
575 | | |
576 | 4 | if (size < 0) { |
577 | 0 | zend_argument_value_error(1, "must be greater than or equal to 0"); |
578 | 0 | RETURN_THROWS(); |
579 | 0 | } |
580 | | |
581 | 4 | intern = Z_SPLFIXEDARRAY_P(object); |
582 | | |
583 | 4 | if (UNEXPECTED(!spl_fixedarray_empty(&intern->array) || spl_fixedarray_resize_in_progress(&intern->array))) { |
584 | | /* called __construct() twice, bail out */ |
585 | 0 | return; |
586 | 0 | } |
587 | | |
588 | 4 | if (UNEXPECTED(spl_fixedarray_init(&intern->array, size) == FAILURE)) { |
589 | 0 | RETURN_OOM(); |
590 | 0 | } |
591 | 4 | } |
592 | | |
593 | | PHP_METHOD(SplFixedArray, __wakeup) |
594 | 0 | { |
595 | 0 | spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
596 | 0 | HashTable *intern_ht = zend_std_get_properties(Z_OBJ_P(ZEND_THIS)); |
597 | 0 | zval *data; |
598 | |
|
599 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
600 | | |
601 | 0 | if (EXPECTED(intern->array.size == 0 && !spl_fixedarray_resize_in_progress(&intern->array))) { |
602 | 0 | int index = 0; |
603 | 0 | int size = zend_hash_num_elements(intern_ht); |
604 | |
|
605 | 0 | if (UNEXPECTED(spl_fixedarray_init(&intern->array, size) == FAILURE)) { |
606 | 0 | RETURN_OOM(); |
607 | 0 | } |
608 | | |
609 | 0 | ZEND_HASH_FOREACH_VAL(intern_ht, data) { |
610 | 0 | ZVAL_COPY(&intern->array.elements[index], data); |
611 | 0 | index++; |
612 | 0 | } ZEND_HASH_FOREACH_END(); |
613 | | |
614 | | /* Remove the unserialised properties, since we now have the elements |
615 | | * within the spl_fixedarray_object structure. */ |
616 | 0 | zend_hash_clean(intern_ht); |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | | PHP_METHOD(SplFixedArray, __serialize) |
621 | 0 | { |
622 | 0 | spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
623 | 0 | zval *current; |
624 | 0 | zend_string *key; |
625 | |
|
626 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
627 | | |
628 | 0 | HashTable *ht = zend_std_get_properties(&intern->std); |
629 | 0 | uint32_t num_properties = zend_hash_num_elements(ht); |
630 | 0 | array_init_size(return_value, intern->array.size + num_properties); |
631 | | |
632 | | /* elements */ |
633 | 0 | for (zend_long i = 0; i < intern->array.size; i++) { |
634 | 0 | current = &intern->array.elements[i]; |
635 | 0 | zend_hash_next_index_insert(Z_ARRVAL_P(return_value), current); |
636 | 0 | Z_TRY_ADDREF_P(current); |
637 | 0 | } |
638 | | |
639 | | /* members */ |
640 | 0 | ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, key, current) { |
641 | | /* If the properties table was already rebuild, it will also contain the |
642 | | * array elements. The array elements are already added in the above loop. |
643 | | * We can detect array elements by the fact that their key == NULL. */ |
644 | 0 | if (key != NULL) { |
645 | 0 | zend_hash_add_new(Z_ARRVAL_P(return_value), key, current); |
646 | 0 | Z_TRY_ADDREF_P(current); |
647 | 0 | } |
648 | 0 | } ZEND_HASH_FOREACH_END(); |
649 | 0 | } |
650 | | |
651 | | PHP_METHOD(SplFixedArray, __unserialize) |
652 | 5.45k | { |
653 | 5.45k | spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
654 | 5.45k | HashTable *data; |
655 | 5.45k | zval members_zv, *elem; |
656 | 5.45k | zend_string *key; |
657 | 5.45k | zend_long size; |
658 | | |
659 | 5.45k | if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { |
660 | 0 | RETURN_THROWS(); |
661 | 0 | } |
662 | | |
663 | 5.45k | if (EXPECTED(intern->array.size == 0 && !spl_fixedarray_resize_in_progress(&intern->array))) { |
664 | 5.45k | size = zend_hash_num_elements(data); |
665 | 5.45k | if (UNEXPECTED(spl_fixedarray_init_non_empty_struct(&intern->array, size) == FAILURE)) { |
666 | 0 | RETURN_OOM(); |
667 | 0 | } |
668 | 5.45k | if (!size) { |
669 | 4 | return; |
670 | 4 | } |
671 | 5.45k | array_init(&members_zv); |
672 | | |
673 | 5.45k | intern->array.size = 0; |
674 | 35.2k | ZEND_HASH_FOREACH_STR_KEY_VAL(data, key, elem) { |
675 | 35.2k | if (key == NULL) { |
676 | 8.32k | ZVAL_COPY_DEREF(&intern->array.elements[intern->array.size], elem); |
677 | 8.32k | intern->array.size++; |
678 | 8.32k | } else { |
679 | 6.58k | Z_TRY_ADDREF_P(elem); |
680 | 6.58k | zend_hash_add(Z_ARRVAL(members_zv), key, elem); |
681 | 6.58k | } |
682 | 35.2k | } ZEND_HASH_FOREACH_END(); |
683 | | |
684 | 5.45k | if (intern->array.size != size) { |
685 | 3.30k | if (intern->array.size) { |
686 | 3 | intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * intern->array.size); |
687 | 3.29k | } else { |
688 | 3.29k | efree(intern->array.elements); |
689 | 3.29k | intern->array.elements = NULL; |
690 | 3.29k | } |
691 | 3.30k | } |
692 | | |
693 | 5.45k | object_properties_load(&intern->std, Z_ARRVAL(members_zv)); |
694 | 5.45k | zval_ptr_dtor(&members_zv); |
695 | 5.45k | } |
696 | 5.45k | } |
697 | | |
698 | | PHP_METHOD(SplFixedArray, count) |
699 | 0 | { |
700 | 0 | zval *object = ZEND_THIS; |
701 | 0 | spl_fixedarray_object *intern; |
702 | |
|
703 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
704 | | |
705 | 0 | intern = Z_SPLFIXEDARRAY_P(object); |
706 | 0 | RETURN_LONG(intern->array.size); |
707 | 0 | } |
708 | | |
709 | | PHP_METHOD(SplFixedArray, toArray) |
710 | 0 | { |
711 | 0 | spl_fixedarray_object *intern; |
712 | |
|
713 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
714 | | |
715 | 0 | intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
716 | |
|
717 | 0 | if (!spl_fixedarray_empty(&intern->array)) { |
718 | 0 | array_init_size(return_value, intern->array.size); |
719 | 0 | HashTable *ht = Z_ARRVAL_P(return_value); |
720 | 0 | zend_hash_real_init_packed(ht); |
721 | |
|
722 | 0 | ZEND_HASH_FILL_PACKED(ht) { |
723 | 0 | for (zend_long i = 0; i < intern->array.size; i++) { |
724 | 0 | ZEND_HASH_FILL_ADD(&intern->array.elements[i]); |
725 | 0 | Z_TRY_ADDREF(intern->array.elements[i]); |
726 | 0 | } |
727 | 0 | } ZEND_HASH_FILL_END(); |
728 | 0 | } else { |
729 | 0 | RETURN_EMPTY_ARRAY(); |
730 | 0 | } |
731 | 0 | } |
732 | | |
733 | | PHP_METHOD(SplFixedArray, fromArray) |
734 | 1 | { |
735 | 1 | zval *data; |
736 | 1 | spl_fixedarray array; |
737 | 1 | spl_fixedarray_object *intern; |
738 | 1 | int num; |
739 | 1 | bool save_indexes = true; |
740 | | |
741 | 1 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &data, &save_indexes) == FAILURE) { |
742 | 0 | RETURN_THROWS(); |
743 | 0 | } |
744 | | |
745 | 1 | num = zend_hash_num_elements(Z_ARRVAL_P(data)); |
746 | | |
747 | 1 | if (num > 0 && save_indexes) { |
748 | 0 | zval *element; |
749 | 0 | zend_string *str_index; |
750 | 0 | zend_ulong num_index, max_index = 0; |
751 | 0 | zend_long tmp; |
752 | |
|
753 | 0 | if (HT_IS_PACKED(Z_ARRVAL_P(data))) { |
754 | | /* If there are no holes, then nNumUsed is the number of elements. |
755 | | * If there are holes, then nNumUsed is the index of the last element. */ |
756 | 0 | tmp = Z_ARRVAL_P(data)->nNumUsed; |
757 | 0 | } else { |
758 | 0 | ZEND_HASH_MAP_FOREACH_KEY(Z_ARRVAL_P(data), num_index, str_index) { |
759 | 0 | if (str_index != NULL || (zend_long)num_index < 0) { |
760 | 0 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array must contain only positive integer keys"); |
761 | 0 | RETURN_THROWS(); |
762 | 0 | } |
763 | | |
764 | 0 | if (num_index > max_index) { |
765 | 0 | max_index = num_index; |
766 | 0 | } |
767 | 0 | } ZEND_HASH_FOREACH_END(); |
768 | | |
769 | 0 | tmp = max_index + 1; |
770 | 0 | if (tmp <= 0) { |
771 | 0 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "integer overflow detected"); |
772 | 0 | RETURN_THROWS(); |
773 | 0 | } |
774 | 0 | } |
775 | | |
776 | 0 | if (UNEXPECTED(spl_fixedarray_init(&array, tmp) == FAILURE)) { |
777 | 0 | RETURN_OOM(); |
778 | 0 | } |
779 | | |
780 | 0 | ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(data), num_index, element) { |
781 | 0 | ZVAL_COPY_DEREF(&array.elements[num_index], element); |
782 | 0 | } ZEND_HASH_FOREACH_END(); |
783 | |
|
784 | 1 | } else if (num > 0 && !save_indexes) { |
785 | 1 | zval *element; |
786 | 1 | zend_long i = 0; |
787 | | |
788 | 1 | if (UNEXPECTED(spl_fixedarray_init(&array, num) == FAILURE)) { |
789 | 0 | RETURN_OOM(); |
790 | 0 | } |
791 | | |
792 | 262k | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(data), element) { |
793 | 262k | ZVAL_COPY_DEREF(&array.elements[i], element); |
794 | 262k | i++; |
795 | 262k | } ZEND_HASH_FOREACH_END(); |
796 | 1 | } else { |
797 | 0 | if (UNEXPECTED(spl_fixedarray_init(&array, 0) == FAILURE)) { |
798 | 0 | RETURN_OOM(); |
799 | 0 | } |
800 | 0 | } |
801 | | |
802 | 1 | object_init_ex(return_value, spl_ce_SplFixedArray); |
803 | | |
804 | 1 | intern = Z_SPLFIXEDARRAY_P(return_value); |
805 | 1 | intern->array = array; |
806 | 1 | } |
807 | | |
808 | | PHP_METHOD(SplFixedArray, getSize) |
809 | 0 | { |
810 | 0 | zval *object = ZEND_THIS; |
811 | 0 | spl_fixedarray_object *intern; |
812 | |
|
813 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
814 | | |
815 | 0 | intern = Z_SPLFIXEDARRAY_P(object); |
816 | 0 | RETURN_LONG(intern->array.size); |
817 | 0 | } |
818 | | |
819 | | PHP_METHOD(SplFixedArray, setSize) |
820 | 0 | { |
821 | 0 | zval *object = ZEND_THIS; |
822 | 0 | spl_fixedarray_object *intern; |
823 | 0 | zend_long size; |
824 | |
|
825 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) { |
826 | 0 | RETURN_THROWS(); |
827 | 0 | } |
828 | | |
829 | 0 | if (size < 0) { |
830 | 0 | zend_argument_value_error(1, "must be greater than or equal to 0"); |
831 | 0 | RETURN_THROWS(); |
832 | 0 | } |
833 | | |
834 | 0 | intern = Z_SPLFIXEDARRAY_P(object); |
835 | |
|
836 | 0 | if (UNEXPECTED(spl_fixedarray_resize(&intern->array, size) == FAILURE)) { |
837 | 0 | RETURN_OOM(); |
838 | 0 | } |
839 | | |
840 | 0 | RETURN_TRUE; |
841 | 0 | } |
842 | | |
843 | | /* Returns whether the requested $index exists. */ |
844 | | PHP_METHOD(SplFixedArray, offsetExists) |
845 | 0 | { |
846 | 0 | zval *zindex; |
847 | 0 | spl_fixedarray_object *intern; |
848 | |
|
849 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) { |
850 | 0 | RETURN_THROWS(); |
851 | 0 | } |
852 | | |
853 | 0 | intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
854 | |
|
855 | 0 | RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, false)); |
856 | 0 | } |
857 | | |
858 | | /* Returns the value at the specified $index. */ |
859 | | PHP_METHOD(SplFixedArray, offsetGet) |
860 | 0 | { |
861 | 0 | zval *zindex, *value; |
862 | 0 | spl_fixedarray_object *intern; |
863 | |
|
864 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) { |
865 | 0 | RETURN_THROWS(); |
866 | 0 | } |
867 | | |
868 | 0 | intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
869 | 0 | value = spl_fixedarray_object_read_dimension_helper(intern, zindex); |
870 | |
|
871 | 0 | if (value) { |
872 | 0 | RETURN_COPY(value); |
873 | 0 | } else { |
874 | 0 | RETURN_NULL(); |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | | /* Sets the value at the specified $index to $newval. */ |
879 | | PHP_METHOD(SplFixedArray, offsetSet) |
880 | 0 | { |
881 | 0 | zval *zindex, *value; |
882 | 0 | spl_fixedarray_object *intern; |
883 | |
|
884 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zindex, &value) == FAILURE) { |
885 | 0 | RETURN_THROWS(); |
886 | 0 | } |
887 | | |
888 | 0 | intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
889 | 0 | spl_fixedarray_object_write_dimension_helper(intern, zindex, value); |
890 | |
|
891 | 0 | } |
892 | | |
893 | | /* Unsets the value at the specified $index. */ |
894 | | PHP_METHOD(SplFixedArray, offsetUnset) |
895 | 0 | { |
896 | 0 | zval *zindex; |
897 | 0 | spl_fixedarray_object *intern; |
898 | |
|
899 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) { |
900 | 0 | RETURN_THROWS(); |
901 | 0 | } |
902 | | |
903 | 0 | intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); |
904 | 0 | spl_fixedarray_object_unset_dimension_helper(intern, zindex); |
905 | |
|
906 | 0 | } |
907 | | |
908 | | /* Create a new iterator from a SplFixedArray instance. */ |
909 | | PHP_METHOD(SplFixedArray, getIterator) |
910 | 0 | { |
911 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
912 | | |
913 | 0 | zend_create_internal_iterator_zval(return_value, ZEND_THIS); |
914 | 0 | } |
915 | | |
916 | | static void spl_fixedarray_it_dtor(zend_object_iterator *iter) |
917 | 0 | { |
918 | 0 | zval_ptr_dtor(&iter->data); |
919 | 0 | } |
920 | | |
921 | | static void spl_fixedarray_it_rewind(zend_object_iterator *iter) |
922 | 0 | { |
923 | 0 | ((spl_fixedarray_it*)iter)->current = 0; |
924 | 0 | } |
925 | | |
926 | | static zend_result spl_fixedarray_it_valid(zend_object_iterator *iter) |
927 | 0 | { |
928 | 0 | spl_fixedarray_it *iterator = (spl_fixedarray_it*)iter; |
929 | 0 | spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data); |
930 | |
|
931 | 0 | if (iterator->current >= 0 && iterator->current < object->array.size) { |
932 | 0 | return SUCCESS; |
933 | 0 | } |
934 | | |
935 | 0 | return FAILURE; |
936 | 0 | } |
937 | | |
938 | | static zval *spl_fixedarray_it_get_current_data(zend_object_iterator *iter) |
939 | 0 | { |
940 | 0 | zval zindex, *data; |
941 | 0 | spl_fixedarray_it *iterator = (spl_fixedarray_it*)iter; |
942 | 0 | spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data); |
943 | |
|
944 | 0 | ZVAL_LONG(&zindex, iterator->current); |
945 | 0 | data = spl_fixedarray_object_read_dimension_helper(object, &zindex); |
946 | |
|
947 | 0 | if (data == NULL) { |
948 | 0 | data = &EG(uninitialized_zval); |
949 | 0 | } |
950 | 0 | return data; |
951 | 0 | } |
952 | | |
953 | | static void spl_fixedarray_it_get_current_key(zend_object_iterator *iter, zval *key) |
954 | 0 | { |
955 | 0 | ZVAL_LONG(key, ((spl_fixedarray_it*)iter)->current); |
956 | 0 | } |
957 | | |
958 | | static void spl_fixedarray_it_move_forward(zend_object_iterator *iter) |
959 | 0 | { |
960 | 0 | ((spl_fixedarray_it*)iter)->current++; |
961 | 0 | } |
962 | | |
963 | | /* iterator handler table */ |
964 | | static const zend_object_iterator_funcs spl_fixedarray_it_funcs = { |
965 | | spl_fixedarray_it_dtor, |
966 | | spl_fixedarray_it_valid, |
967 | | spl_fixedarray_it_get_current_data, |
968 | | spl_fixedarray_it_get_current_key, |
969 | | spl_fixedarray_it_move_forward, |
970 | | spl_fixedarray_it_rewind, |
971 | | NULL, |
972 | | NULL, /* get_gc */ |
973 | | }; |
974 | | |
975 | | static zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref) |
976 | 0 | { |
977 | 0 | spl_fixedarray_it *iterator; |
978 | |
|
979 | 0 | if (by_ref) { |
980 | 0 | zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); |
981 | 0 | return NULL; |
982 | 0 | } |
983 | | |
984 | 0 | iterator = emalloc(sizeof(spl_fixedarray_it)); |
985 | |
|
986 | 0 | zend_iterator_init((zend_object_iterator*)iterator); |
987 | |
|
988 | 0 | ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object)); |
989 | 0 | iterator->intern.funcs = &spl_fixedarray_it_funcs; |
990 | |
|
991 | 0 | return &iterator->intern; |
992 | 0 | } |
993 | | |
994 | | PHP_MINIT_FUNCTION(spl_fixedarray) |
995 | 16 | { |
996 | 16 | spl_ce_SplFixedArray = register_class_SplFixedArray( |
997 | 16 | zend_ce_aggregate, zend_ce_arrayaccess, zend_ce_countable, php_json_serializable_ce); |
998 | 16 | spl_ce_SplFixedArray->create_object = spl_fixedarray_new; |
999 | 16 | spl_ce_SplFixedArray->default_object_handlers = &spl_handler_SplFixedArray; |
1000 | 16 | spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator; |
1001 | | |
1002 | 16 | memcpy(&spl_handler_SplFixedArray, &std_object_handlers, sizeof(zend_object_handlers)); |
1003 | | |
1004 | 16 | spl_handler_SplFixedArray.offset = offsetof(spl_fixedarray_object, std); |
1005 | 16 | spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone; |
1006 | 16 | spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension; |
1007 | 16 | spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension; |
1008 | 16 | spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension; |
1009 | 16 | spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension; |
1010 | 16 | spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements; |
1011 | 16 | spl_handler_SplFixedArray.get_properties_for = spl_fixedarray_object_get_properties_for; |
1012 | 16 | spl_handler_SplFixedArray.get_gc = spl_fixedarray_object_get_gc; |
1013 | 16 | spl_handler_SplFixedArray.free_obj = spl_fixedarray_object_free_storage; |
1014 | | |
1015 | 16 | return SUCCESS; |
1016 | 16 | } |