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
121 changes: 72 additions & 49 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6013,11 +6013,11 @@ ZEND_METHOD(ReflectionProperty, setValue)
* 'scope' on 'object'. The result may be different from 'ref->prop' when the
* 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;
static const zend_property_info *reflection_property_get_effective_prop(
const zend_property_info *prop, zend_string *unmangled_name,
const 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));
const 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(const zend_property_info *prop,
zend_string *unmangled_name, void *cache_slot[3],
const 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(const zend_property_info *prop,
zend_string *unmangled_name, void *cache_slot[3],
const 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)
const zend_property_info *prop, zend_string *unmangled_name,
const 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(
const zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], const 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 @@ -6703,7 +6724,7 @@ ZEND_METHOD(ReflectionProperty, isReadable)

GET_REFLECTION_OBJECT_PTR(ref);

zend_property_info *prop = ref->prop;
const zend_property_info *prop = ref->prop;
if (prop && obj) {
if (prop->flags & ZEND_ACC_STATIC) {
zend_throw_exception(reflection_exception_ptr, "null is expected as object argument for static properties", 0);
Expand All @@ -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 @@ -6809,7 +6831,7 @@ ZEND_METHOD(ReflectionProperty, isWritable)

GET_REFLECTION_OBJECT_PTR(ref);

zend_property_info *prop = ref->prop;
const zend_property_info *prop = ref->prop;
if (prop && obj) {
if (prop->flags & ZEND_ACC_STATIC) {
zend_throw_exception(reflection_exception_ptr, "null is expected as object argument for static properties", 0);
Expand All @@ -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
12 changes: 12 additions & 0 deletions ext/reflection/php_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ 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. */
PHPAPI void zend_reflection_property_set_raw_value(
const zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], const 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(
const zend_property_info *prop, zend_string *unmangled_name,
void *cache_slot[3], const zend_class_entry *scope,
zend_object *object, zval *value);

END_EXTERN_C()

#endif /* PHP_REFLECTION_H */
Loading