php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_property_hooks.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Ilija Tovilo <ilutov@php.net> |
16 +----------------------------------------------------------------------+
17*/
18
19#include "zend.h"
20#include "zend_API.h"
21#include "zend_hash.h"
22#include "zend_lazy_objects.h"
23#include "zend_property_hooks.h"
24
36
37static zend_result zho_it_valid(zend_object_iterator *iter);
38static void zho_it_move_forward(zend_object_iterator *iter);
39
40static uint32_t zho_find_dynamic_prop_offset(zend_array *properties)
41{
42 uint32_t offset = 0;
43 zval *value;
44
45 ZEND_HASH_MAP_FOREACH_VAL(properties, value) {
46 if (Z_TYPE_P(value) != IS_INDIRECT) {
47 break;
48 }
49 offset++;
51
52 return offset;
53}
54
55static zend_array *zho_build_properties_ex(zend_object *zobj, bool check_access, bool force_ptr, bool include_dynamic_props)
56{
57 zend_class_entry *ce = zobj->ce;
58 zend_array *properties = zend_new_array(include_dynamic_props && zobj->properties
59 ? zend_hash_num_elements(zobj->properties)
61 zend_hash_real_init_mixed(properties);
62
63 /* Build list of parents */
64 int32_t parent_count = 0;
65 for (zend_class_entry *pce = ce; pce; pce = pce->parent) {
66 parent_count++;
67 }
68 zend_class_entry **parents = emalloc(sizeof(zend_class_entry*) * parent_count);
69 int32_t i = 0;
70 for (zend_class_entry *pce = ce; pce; pce = pce->parent) {
71 parents[i++] = pce;
72 }
73
74 /* Iterate parents top to bottom */
75 i--;
76 for (; i >= 0; i--) {
77 zend_class_entry *pce = parents[i];
78
81 if (prop_info->flags & ZEND_ACC_STATIC) {
82 continue;
83 }
84 zend_string *property_name = prop_info->name;
85 /* When promoting properties from protected to public, use the unmangled name to preserve order. */
86 if (prop_info->flags & ZEND_ACC_PROTECTED) {
87 const char *tmp = zend_get_unmangled_property_name(property_name);
88 zend_string *unmangled_name = zend_string_init(tmp, strlen(tmp), false);
89 zend_property_info *child_prop_info = zend_hash_find_ptr(&ce->properties_info, unmangled_name);
90 if (child_prop_info && (child_prop_info->flags & ZEND_ACC_PUBLIC)) {
91 property_name = unmangled_name;
92 } else {
93 zend_string_release(unmangled_name);
94 }
95 }
96 if (check_access && zend_check_property_access(zobj, property_name, false) == FAILURE) {
97 goto skip_property;
98 }
99 if (prop_info->hooks || force_ptr) {
100 zend_hash_update_ptr(properties, property_name, prop_info);
101 } else {
102 if (UNEXPECTED(Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) == IS_UNDEF)) {
103 HT_FLAGS(properties) |= HASH_FLAG_HAS_EMPTY_IND;
104 }
105 zval *tmp = zend_hash_lookup(properties, property_name);
106 ZVAL_INDIRECT(tmp, OBJ_PROP(zobj, prop_info->offset));
107 }
108skip_property:
109 if (property_name != prop_info->name) {
110 zend_string_release(property_name);
111 }
113 }
114
115 efree(parents);
116
117 if (include_dynamic_props && zobj->properties) {
118 zend_string *prop_name;
119 zval *prop_value;
120 ZEND_HASH_FOREACH_STR_KEY_VAL(zobj->properties, prop_name, prop_value) {
121 if (Z_TYPE_P(prop_value) == IS_INDIRECT) {
122 continue;
123 }
124 zval *tmp = _zend_hash_append(properties, prop_name, prop_value);
125 Z_TRY_ADDREF_P(tmp);
127 }
128
129 return properties;
130}
131
133{
134 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
136 if (UNEXPECTED(!zobj)) {
137 return (zend_array*) &zend_empty_array;
138 }
139 }
140
141 return zho_build_properties_ex(zobj, false, false, true);
142}
143
144static void zho_dynamic_it_init(zend_hooked_object_iterator *hooked_iter)
145{
146 zend_object *zobj = Z_OBJ_P(&hooked_iter->it.data);
147 zend_array *properties = zobj->handlers->get_properties(zobj);
148 hooked_iter->dynamic_props_done = false;
149 hooked_iter->dynamic_prop_offset = zho_find_dynamic_prop_offset(properties);
150 hooked_iter->dynamic_prop_it = zend_hash_iterator_add(properties, hooked_iter->dynamic_prop_offset);
151}
152
153static void zho_it_get_current_key(zend_object_iterator *iter, zval *key);
154
155static void zho_declared_it_fetch_current(zend_object_iterator *iter)
156{
158 zend_object *zobj = Z_OBJ_P(&iter->data);
159 zend_array *properties = Z_ARR(hooked_iter->declared_props);
160
161 zend_property_info *prop_info = Z_PTR_P(zend_hash_get_current_data(properties));
162 if (prop_info->hooks) {
164 if (!get && (prop_info->flags & ZEND_ACC_VIRTUAL)) {
165 return;
166 }
167 if (hooked_iter->by_ref
168 && (get == NULL
170 zend_throw_error(NULL, "Cannot create reference to property %s::$%s",
171 ZSTR_VAL(zobj->ce->name), zend_get_unmangled_property_name(prop_info->name));
172 return;
173 }
174 zend_string *unmangled_name = prop_info->name;
175 if (ZSTR_VAL(unmangled_name)[0] == '\0') {
176 const char *tmp = zend_get_unmangled_property_name(unmangled_name);
177 unmangled_name = zend_string_init(tmp, strlen(tmp), false);
178 }
179 zval *value = zend_read_property_ex(prop_info->ce, zobj, unmangled_name, /* silent */ true, &hooked_iter->current_data);
180 if (unmangled_name != prop_info->name) {
181 zend_string_release(unmangled_name);
182 }
183 if (value == &EG(uninitialized_zval)) {
184 return;
185 } else if (value != &hooked_iter->current_data) {
186 ZVAL_COPY(&hooked_iter->current_data, value);
187 }
188 } else {
189 zval *property = OBJ_PROP(zobj, prop_info->offset);
191 if (Z_TYPE_P(property) == IS_UNDEF) {
192 return;
193 }
194 if (!hooked_iter->by_ref) {
196 } else if (Z_TYPE_P(property) != IS_REFERENCE) {
197 if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
199 "Cannot acquire reference to readonly property %s::$%s",
200 ZSTR_VAL(prop_info->ce->name), zend_get_unmangled_property_name(prop_info->name));
201 return;
202 }
204 if (ZEND_TYPE_IS_SET(prop_info->type)) {
206 }
207 }
208 ZVAL_COPY(&hooked_iter->current_data, property);
209 }
210
211 if (ZSTR_VAL(prop_info->name)[0] == '\0') {
212 const char *tmp = zend_get_unmangled_property_name(prop_info->name);
213 ZVAL_STR(&hooked_iter->current_key, zend_string_init(tmp, strlen(tmp), false));
214 } else {
215 ZVAL_STR_COPY(&hooked_iter->current_key, prop_info->name);
216 }
217}
218
219static void zho_dynamic_it_fetch_current(zend_object_iterator *iter)
220{
222 zend_array *properties = Z_OBJ(iter->data)->properties;
223 HashPosition pos = zend_hash_iterator_pos(hooked_iter->dynamic_prop_it, properties);
224
225 if (pos >= properties->nNumUsed) {
226 hooked_iter->dynamic_props_done = true;
227 return;
228 }
229
230 Bucket *bucket = properties->arData + pos;
231
232 if (UNEXPECTED(Z_TYPE(bucket->val) == IS_UNDEF)) {
233 return;
234 }
235
236 zend_object *zobj = Z_OBJ_P(&hooked_iter->it.data);
237 if (bucket->key && zend_check_property_access(zobj, bucket->key, true) != SUCCESS) {
238 return;
239 }
240
241 if (hooked_iter->by_ref && Z_TYPE(bucket->val) != IS_REFERENCE) {
242 ZVAL_MAKE_REF(&bucket->val);
243 }
244 ZVAL_COPY(&hooked_iter->current_data, &bucket->val);
245
246 if (bucket->key) {
247 ZVAL_STR_COPY(&hooked_iter->current_key, bucket->key);
248 } else {
249 ZVAL_LONG(&hooked_iter->current_key, bucket->h);
250 }
251}
252
253static void zho_it_fetch_current(zend_object_iterator *iter)
254{
256 if (Z_TYPE(hooked_iter->current_data) != IS_UNDEF) {
257 return;
258 }
259
260 while (true) {
261 if (!hooked_iter->declared_props_done) {
262 zho_declared_it_fetch_current(iter);
263 } else if (!hooked_iter->dynamic_props_done) {
264 zho_dynamic_it_fetch_current(iter);
265 } else {
266 break;
267 }
268 if (Z_TYPE(hooked_iter->current_data) != IS_UNDEF || EG(exception)) {
269 break;
270 }
271 zho_it_move_forward(iter);
272 }
273}
274
275static void zho_it_dtor(zend_object_iterator *iter)
276{
278 zval_ptr_dtor(&iter->data);
279 zval_ptr_dtor(&hooked_iter->declared_props);
280 zval_ptr_dtor_nogc(&hooked_iter->current_key);
281 zval_ptr_dtor(&hooked_iter->current_data);
283}
284
285static zend_result zho_it_valid(zend_object_iterator *iter)
286{
288 zho_it_fetch_current(iter);
289 return Z_TYPE(hooked_iter->current_data) != IS_UNDEF ? SUCCESS : FAILURE;
290}
291
292static zval *zho_it_get_current_data(zend_object_iterator *iter)
293{
295 zho_it_fetch_current(iter);
296 return &hooked_iter->current_data;
297}
298
299static void zho_it_get_current_key(zend_object_iterator *iter, zval *key)
300{
302 zho_it_fetch_current(iter);
303 ZVAL_COPY(key, &hooked_iter->current_key);
304}
305
306static void zho_it_move_forward(zend_object_iterator *iter)
307{
309
310 zval_ptr_dtor(&hooked_iter->current_data);
311 ZVAL_UNDEF(&hooked_iter->current_data);
312 zval_ptr_dtor_nogc(&hooked_iter->current_key);
313 ZVAL_UNDEF(&hooked_iter->current_key);
314
315 if (!hooked_iter->declared_props_done) {
316 zend_array *properties = Z_ARR(hooked_iter->declared_props);
317 zend_hash_move_forward(properties);
318 if (zend_hash_has_more_elements(properties) != SUCCESS) {
319 hooked_iter->declared_props_done = true;
320 }
321 } else if (!hooked_iter->dynamic_props_done) {
322 zend_array *properties = Z_OBJ(iter->data)->properties;
323 HashPosition pos = zend_hash_iterator_pos(hooked_iter->dynamic_prop_it, properties);
324 pos++;
325 EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = pos;
326 }
327}
328
329static void zho_it_rewind(zend_object_iterator *iter)
330{
332
333 zval_ptr_dtor(&hooked_iter->current_data);
334 ZVAL_UNDEF(&hooked_iter->current_data);
335 zval_ptr_dtor_nogc(&hooked_iter->current_key);
336 ZVAL_UNDEF(&hooked_iter->current_key);
337
338 zend_array *properties = Z_ARR(hooked_iter->declared_props);
339 zend_hash_internal_pointer_reset(properties);
340 hooked_iter->declared_props_done = !zend_hash_num_elements(properties);
341 hooked_iter->dynamic_props_done = false;
342 EG(ht_iterators)[hooked_iter->dynamic_prop_it].pos = hooked_iter->dynamic_prop_offset;
343}
344
345static HashTable *zho_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
346{
349 zend_get_gc_buffer_add_zval(gc_buffer, &iter->data);
350 zend_get_gc_buffer_add_zval(gc_buffer, &hooked_iter->declared_props);
351 zend_get_gc_buffer_add_zval(gc_buffer, &hooked_iter->current_data);
352 zend_get_gc_buffer_use(gc_buffer, table, n);
353 return NULL;
354}
355
356static const zend_object_iterator_funcs zend_hooked_object_it_funcs = {
357 zho_it_dtor,
358 zho_it_valid,
359 zho_it_get_current_data,
360 zho_it_get_current_key,
361 zho_it_move_forward,
362 zho_it_rewind,
363 NULL,
364 zho_it_get_gc,
365};
366
368{
369 zend_object *zobj = Z_OBJ_P(object);
370 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
372 if (UNEXPECTED(!zobj)) {
373 return NULL;
374 }
375 }
376
378 zend_iterator_init(&iterator->it);
379
380 ZVAL_OBJ_COPY(&iterator->it.data, zobj);
381 iterator->it.funcs = &zend_hooked_object_it_funcs;
382 iterator->by_ref = by_ref;
383 zend_array *properties = zho_build_properties_ex(zobj, true, true, false);
384 ZVAL_ARR(&iterator->declared_props, properties);
385 iterator->declared_props_done = !zend_hash_num_elements(properties);
386 zho_dynamic_it_init(iterator);
387 ZVAL_UNDEF(&iterator->current_key);
388 ZVAL_UNDEF(&iterator->current_data);
389
390 return &iterator->it;
391}
bool exception
Definition assert.c:30
zend_long n
Definition ffi.c:4979
zend_long offset
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
unsigned const char * pos
Definition php_ffi.h:52
unsigned char key[REFLECTION_KEY_LEN]
zend_ulong h
Definition zend_types.h:382
zend_string * key
Definition zend_types.h:383
zval val
Definition zend_types.h:381
uint32_t nNumUsed
Definition zend_types.h:406
Bucket * arData
Definition zend_types.h:403
HashTable properties_info
Definition zend.h:164
int default_properties_count
Definition zend.h:158
const zend_object_iterator_funcs * funcs
struct _zend_function::@236135173067030250234125302313220025134003177336 common
uint32_t fn_flags
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API zval * zend_read_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, bool silent, zval *rv)
Definition zend_API.c:5187
#define efree(ptr)
Definition zend_alloc.h:155
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
#define ZEND_ACC_READONLY
#define OBJ_PROP(obj, offset)
struct _zend_property_info zend_property_info
#define ZEND_ACC_STATIC
#define ZEND_ACC_PUBLIC
#define ZEND_ACC_VIRTUAL
#define ZEND_ACC_RETURN_REFERENCE
#define ZEND_ACC_PROTECTED
#define ZEND_API
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source)
union _zend_function zend_function
ZEND_API zend_get_gc_buffer * zend_get_gc_buffer_create(void)
Definition zend_gc.c:2130
#define EG(v)
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
Definition zend_hash.c:537
ZEND_API zval *ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key)
Definition zend_hash.c:1012
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
Definition zend_hash.c:608
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
Definition zend_hash.c:338
ZEND_API const HashTable zend_empty_array
Definition zend_hash.c:248
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
Definition zend_hash.c:649
#define ZEND_HASH_MAP_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1310
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define zend_new_array(size)
Definition zend_hash.h:338
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1166
#define HT_FLAGS(ht)
Definition zend_hash.h:50
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define HASH_FLAG_HAS_EMPTY_IND
Definition zend_hash.h:44
ZEND_API void zend_iterator_init(zend_object_iterator *iter)
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
ZEND_API zend_object * zend_lazy_object_init(zend_object *obj)
struct _zend_string zend_string
ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic)
#define UNEXPECTED(condition)
ZEND_API zend_array * zend_hooked_object_build_properties(zend_object *zobj)
ZEND_API zend_object_iterator * zend_hooked_object_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
struct _zend_array zend_array
@ ZEND_PROPERTY_HOOK_GET
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_STR(z, s)
#define Z_TRY_ADDREF_P(pz)
#define ZVAL_UNDEF(z)
#define IS_UNDEF
Definition zend_types.h:600
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define ZVAL_STR_COPY(z, s)
#define ZVAL_INDIRECT(z, v)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define Z_PTR_P(zval_p)
@ FAILURE
Definition zend_types.h:61
#define ZVAL_ARR(z, a)
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
#define IS_REFERENCE
Definition zend_types.h:610
#define ZVAL_MAKE_REF(zv)
#define ZVAL_COPY(z, v)
uint32_t HashPosition
Definition zend_types.h:548
#define Z_ARR(zval)
Definition zend_types.h:983
struct _Bucket Bucket
#define Z_REF_P(zval_p)
#define ZVAL_OBJ_COPY(z, o)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define Z_TYPE(zval)
Definition zend_types.h:659
#define IS_INDIRECT
Definition zend_types.h:623
#define ZVAL_DEINDIRECT(z)
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zend_property_info * prop_info
value
property
zend_object * zobj