Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 68 additions & 45 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6014,10 +6014,10 @@ ZEND_METHOD(ReflectionProperty, setValue)
* property is overridden on 'object' and was not private in 'scope'.
* The effective prop may add hooks or change flags. */
static zend_property_info *reflection_property_get_effective_prop(
property_reference *ref, zend_class_entry *scope, zend_object *object) {
zend_property_info *prop = ref->prop;
zend_property_info *prop, zend_string *unmangled_name,
zend_class_entry *scope, zend_object *object) {
if (scope != object->ce && !(prop && (prop->flags & ZEND_ACC_PRIVATE))) {
prop = zend_hash_find_ptr(&object->ce->properties_info, ref->unmangled_name);
prop = zend_hash_find_ptr(&object->ce->properties_info, unmangled_name);
}
return prop;
}
Expand Down Expand Up @@ -6050,8 +6050,8 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
}
}

zend_property_info *prop = reflection_property_get_effective_prop(ref,
intern->ce, Z_OBJ_P(object));
zend_property_info *prop = reflection_property_get_effective_prop(ref->prop,
ref->unmangled_name, intern->ce, Z_OBJ_P(object));

if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
zend_throw_exception(reflection_exception_ptr, "May not use getRawValue on static properties", 0);
Expand Down Expand Up @@ -6081,13 +6081,15 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
}
}

static void reflection_property_set_raw_value(zend_property_info *prop,
zend_string *unmangled_name, void *cache_slot[3], reflection_object *intern,
zend_object *object, zval *value)
static void zend_reflection_property_set_raw_value_ex(zend_property_info *prop,
zend_string *unmangled_name, void *cache_slot[3],
zend_class_entry *scope, zend_object *object, zval *value)
{
ZEND_ASSERT(!prop || !(prop->flags & ZEND_ACC_STATIC));

if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
const zend_class_entry *old_scope = EG(fake_scope);
EG(fake_scope) = intern->ce;
EG(fake_scope) = scope;
object->handlers->write_property(object, unmangled_name, value, cache_slot);
EG(fake_scope) = old_scope;
} else {
Expand All @@ -6096,6 +6098,22 @@ static void reflection_property_set_raw_value(zend_property_info *prop,
}
}

PHPAPI void zend_reflection_property_set_raw_value(zend_property_info *prop,
zend_string *unmangled_name, void *cache_slot[3],
zend_class_entry *scope, zend_object *object, zval *value)
{
prop = reflection_property_get_effective_prop(prop,
unmangled_name, scope, object);

if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
zend_throw_exception(reflection_exception_ptr, "May not use setRawValue on static properties", 0);
return;
}

zend_reflection_property_set_raw_value_ex(prop, unmangled_name, cache_slot,
scope, object, value);
}

ZEND_METHOD(ReflectionProperty, setRawValue)
{
reflection_object *intern;
Expand All @@ -6110,26 +6128,18 @@ ZEND_METHOD(ReflectionProperty, setRawValue)
Z_PARAM_ZVAL(value)
} ZEND_PARSE_PARAMETERS_END();

zend_property_info *prop = reflection_property_get_effective_prop(ref,
intern->ce, Z_OBJ_P(object));

if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
zend_throw_exception(reflection_exception_ptr, "May not use setRawValue on static properties", 0);
RETURN_THROWS();
}

reflection_property_set_raw_value(prop, ref->unmangled_name,
ref->cache_slot, intern, Z_OBJ_P(object), value);
zend_reflection_property_set_raw_value(ref->prop, ref->unmangled_name,
ref->cache_slot, intern->ce, Z_OBJ_P(object), value);
}

static zend_result reflection_property_check_lazy_compatible(
zend_property_info *prop, zend_string *unmangled_name,
reflection_object *intern, zend_object *object, const char *method)
zend_class_entry *scope, zend_object *object, const char *method)
{
if (!prop) {
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Can not use %s on dynamic property %s::$%s",
method, ZSTR_VAL(intern->ce->name),
method, ZSTR_VAL(scope->name),
ZSTR_VAL(unmangled_name));
return FAILURE;
}
Expand Down Expand Up @@ -6164,32 +6174,23 @@ static zend_result reflection_property_check_lazy_compatible(
return SUCCESS;
}

/* {{{ Set property value without triggering initializer while skipping hooks if any */
ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
PHPAPI void zend_reflection_property_set_raw_value_without_lazy_initialization(
zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], zend_class_entry *scope,
zend_object *object, zval *value)
{
reflection_object *intern;
property_reference *ref;
zend_object *object;
zval *value;

GET_REFLECTION_OBJECT_PTR(ref);

ZEND_PARSE_PARAMETERS_START(2, 2) {
Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
Z_PARAM_ZVAL(value)
} ZEND_PARSE_PARAMETERS_END();

while (zend_object_is_lazy_proxy(object)
&& zend_lazy_object_initialized(object)) {
object = zend_lazy_object_get_instance(object);
}

zend_property_info *prop = reflection_property_get_effective_prop(ref,
intern->ce, object);
prop = reflection_property_get_effective_prop(prop,
unmangled_name, scope, object);

if (reflection_property_check_lazy_compatible(prop, ref->unmangled_name,
intern, object, "setRawValueWithoutLazyInitialization") == FAILURE) {
RETURN_THROWS();
if (reflection_property_check_lazy_compatible(prop, unmangled_name,
scope, object, "setRawValueWithoutLazyInitialization") == FAILURE) {
ZEND_ASSERT(EG(exception));
return;
}

zval *var_ptr = OBJ_PROP(object, prop->offset);
Expand All @@ -6198,8 +6199,8 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
/* Do not trigger initialization */
Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY;

reflection_property_set_raw_value(prop, ref->unmangled_name,
ref->cache_slot, intern, object, value);
zend_reflection_property_set_raw_value_ex(prop, unmangled_name,
cache_slot, scope, object, value);

/* Mark property as lazy again if an exception prevented update */
if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF
Expand All @@ -6218,6 +6219,26 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
}
}

/* {{{ Set property value without triggering initializer while skipping hooks if any */
ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
{
reflection_object *intern;
property_reference *ref;
zend_object *object;
zval *value;

GET_REFLECTION_OBJECT_PTR(ref);

ZEND_PARSE_PARAMETERS_START(2, 2) {
Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
Z_PARAM_ZVAL(value)
} ZEND_PARSE_PARAMETERS_END();

zend_reflection_property_set_raw_value_without_lazy_initialization(
ref->prop, ref->unmangled_name, ref->cache_slot, intern->ce,
object, value);
}

/* {{{ Mark property as non-lazy, and initialize to default value */
ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
{
Expand All @@ -6232,7 +6253,7 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
} ZEND_PARSE_PARAMETERS_END();

if (reflection_property_check_lazy_compatible(ref->prop,
ref->unmangled_name, intern, object,
ref->unmangled_name, intern->ce, object,
"skipLazyInitialization") == FAILURE) {
RETURN_THROWS();
}
Expand Down Expand Up @@ -6713,7 +6734,8 @@ ZEND_METHOD(ReflectionProperty, isReadable)
zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
RETURN_THROWS();
}
prop = reflection_property_get_effective_prop(ref, intern->ce, obj);
prop = reflection_property_get_effective_prop(ref->prop,
ref->unmangled_name, intern->ce, obj);
}

zend_class_entry *ce = obj ? obj->ce : intern->ce;
Expand Down Expand Up @@ -6819,7 +6841,8 @@ ZEND_METHOD(ReflectionProperty, isWritable)
zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
RETURN_THROWS();
}
prop = reflection_property_get_effective_prop(ref, intern->ce, obj);
prop = reflection_property_get_effective_prop(ref->prop,
ref->unmangled_name, intern->ce, obj);
}

zend_class_entry *ce = obj ? obj->ce : intern->ce;
Expand Down
21 changes: 21 additions & 0 deletions ext/reflection/php_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ extern PHPAPI zend_class_entry *reflection_lazy_object_ptr;

PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object);

/* Sets the value of a property, bypassing a set hook if defined.
* 'prop': The property to set
* 'unmangled_name': The name of the property
* 'cache_slot': An opaque pointer used as an internal cache. The same
* cache_slot can be used again with the same 'unmangled_name' and 'scope'.
* Must be zeroed on first use. May be NULL.
* 'scope': The scope from which to set the property
* 'object': The object to set the value on
* 'value': The value to set
*/
PHPAPI void zend_reflection_property_set_raw_value(
zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], zend_class_entry *scope,
zend_object *object, zval *value);

/* Same as zend_reflection_property_set_raw_value(), but skips lazy object initialization. */
PHPAPI void zend_reflection_property_set_raw_value_without_lazy_initialization(
zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], zend_class_entry *scope,
zend_object *object, zval *value);

END_EXTERN_C()

#endif /* PHP_REFLECTION_H */
Loading